MongoDB学习比较-07 C#驱动操作MongoDB

下载驱动

驱动的下载有两种方式:一种是在C#项目中通过NuGet进行安装,另一种是通过下面的链接:https://github.com/mongodb/mongo-csharp-driver/releases 直接下载msi进行安装或zip压缩包。不管哪种方式,其主要的目的都是获取两个dll文件:MongoDB.Bson.dll、MongoDB.Driver.dll。这是在程序中需要引用的两个类库文件。

.NET版本要求

目前最新版的C#驱动是1.9.2,是在 .NET3.5的基础上构建的,所以使用C#驱动时,.NET的版本必须是3.5及其以上。

C#驱动主要包括两个命名空间:MongoDB.Bson和MongoDB.Driver。大多数的类是非线程安全的(线程安全的类有:MongoClient、MongoServer、MongoDatabase、MongoCollection、MongoGridFS、BsonSymbolTable)。所有的静态属性和方法都是线程安全的。

线程安全

如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

线程安全问题都是由全局变量及静态变量引起的:若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

创建数据库连接

创建连接时需要使用到下面几个类:MongoClient、MongoServer、MongoDatabase、MongoCollection。

MongoClient类

该类是MongoDB服务器的根对象,表示MongoDB的客户端(实例)。数据库的连接是在后台自动进行的(通过使用连接池提高性能)。默认情况下,所有的写操作在服务器承认写之前都是阻塞的。

创建一个MongoClient最简单的方式就是使用Connection String,连接字符串具有如下的模式:

mongodb://[username:[email protected]]hostname[:port][/[database][?options]]

[]表示该项是可选的;当在MongoDB服务器上启用了认证时,需要使用到用户名和密码;当username和database同时使用时,需要保证该用户有操作该数据库的权限;当不匹配时,默认的数据库是admin;如果不知道端口号,则默认端口号为27017。

当需要连接到多台服务器时,不同服务器之间使用”,”分割,且端口号不能省略,如:

mongodb://server1:27017,server1:27018

MongoServer类

使用MongoClient的GetServer()方法可以获取到MongoServer实例,该类的GetDatabase()方法可以根据数据库名获取到MongoDatabase实例。该方法具有如下的重载:

MongoDatabase GetDatabase(MongoDatabaseSettings settings)

MongoDatabase GetDatabase(string databaseName)

MongoDatabase GetDatabase(string databaseName, MongoCredentials credentials)

MongoDatabase GetDatabase(string databaseName, MongoCredentials credentials, WriteConcern writeConcern)

MongoDatabase GetDatabase(string databaseName, WriteConcern writeConcern)

下面的代码演示了如何连接到服务器并获取数据库:

MongoClient client = new MongoClient(); // 连接到本地

MongoServer server = client.GetServer();

MongoDatabase database = server.GetDatabase("test"); // 获取test数据库

MongoDatabase类

通过给定数据库名可以获取到MongoDB上的数据库,进而通过该类的GetCollection()方法根据集合名字获取MongoCollection<TDefaultDocument>实例。

MongoCollection类

通过给定集合名并使用MongoDatabase实例的GetCollection方法获取集合对象,一切的增删改查都是在集合对象的基础上实现的。

插入文档

通过MongoCollection<TDefaultDocument>的Insert<TDefaultDocument>()方法可以插入一个文档。TDefaultDocument可以是默认的BsonDocument类型也可以是用户自定义的类型。若是用户自定义的类型,则该类型中必须有Id字段或属性,或者手动指定主键的名称。

public class Book

{

// int Id{get;set;}

string Author {get;set;}

string Title {get;set;}

}

MongoCollection<Book> books = database.GetCollection<Book>("books"); // 获取集合名为books的集合

Book book = new Book {

Author = "Ernest Hemingway",

Title = "For Whom the Bell Tolls"

};

books.Insert(book);

上述的自定义类型Book中没有定义id字段或属性,插入到集合时或默认给每天记录增加_id键,该键为ObjectId类型。插入时不会报错,但当我们从数据库获取数据并将数据转化为Book类型时,就会出错,原因是Book没有id字段,获取到的_id值不知道往哪里赋值。

批量插入

通过MongoCollection<TDefaultDocument>的InsertBatch ()方法可以进行文档的批量插入。

MongoCollection<BsonDocument> books;

BsonDocument[] batch = {

new BsonDocument {

{ "author", "Kurt Vonnegut" },

{ "title", "Cat‘s Cradle" }

},

new BsonDocument {

{ "author", "Kurt Vonnegut" },

{ "title", "Slaughterhouse-Five" }

}

};

books.InsertBatch(batch);

批量插入比单个插入的效率要高,因为只进行一次连接请求和处理头信息。

上面的插入文档和批量插入演示了MongoDB C#驱动插入数据所支持的两种数据类型。总得来说自定义类型比较方便,而且符合ADO.NET和EF的习惯。但是使用自定义类涉及到序列化的问题,即我们可以控制类中的哪些字段或属性以什么样的规则与集合中的键对应。关于序列化的内容,可以参考官方文档:http://docs.mongodb.org/ecosystem/tutorial/use-csharp-driver/

数据查找方法:FindOne()和FindOneAs <TDefaultDocument>()

FindOne()方法是最简单的查找方法,该方法从集合中返回第一个找到的文档(当集合中有多个文档时,并不能知道会返回哪个文档)。

MongoCollection<Book> books;

Book book = books.FindOne();

FindOneAs <TDefaultDocument>()可以将查找到的文档转换成TdefaultDocument类型:

MongoCollection<Book> books;

BsonDocument document = books.FindOneAs<BsonDocument>();

FindAs <TDefaultDocument>()

这个方法通过查询文档作为参数,告诉服务器应该返回哪个文档。

查询文档是ImongoQuery类型,一般使用其实现类QueryDocument构造查询文档:

MongoCollection collection = database.GetCollection("user");

var query = new QueryDocument("key", "value");

collection.FindAs(typeof(BsonDocument), query);

查询文档的构造也可以通过MongoDB.Driver.Builders.Query进行构造,可以构造等值查询等不同类型的文档:

MongoCollection collection = database.GetCollection("user");

var query = Query.EQ("key", "value");

collection.FindAs(typeof(BsonDocument), query);

Save<TDocument>()

该方法组合了Insert方法和Update方法。当保存的文档中的Id值已存在时,则相当于Update()方法,否则相当于Insert()方法。

MongoCollection<BsonDocument> books;

var query = Query.And(

Query.EQ("author", "Kurt Vonnegut"),

Query.EQ("title", "Cats Craddle")

);

BsonDocument book = books.FindOne(query);

if (book != null) {

book["title"] = "Cat‘s Cradle";

books.Save(book);

}

Save方法的Tdocument类型必须要有Id字段,否则,只能使用Insert方法。

Update()方法

该方法用于更新已经存在的文档。上面使用Save方法进行的更新相当于下面的代码:

MongoCollection<BsonDocument> books;

var query = new QueryDocument {

{ "author", "Kurt Vonnegut" },

{ "title", "Cats Craddle" }

};

var update = new UpdateDocument {

{ "$set", new BsonDocument("title", "Cat‘s Cradle") }

};

BsonDocument updatedBook = books.Update(query, update);

也可以使用Query和Update构造器:

MongoCollection<BsonDocument> books;

var query = Query.And(

Query.EQ("author", "Kurt Vonnegut"),

Query.EQ("title", "Cats Craddle")

);

var update = Update.Set("title", "Cat‘s Cradle");

BsonDocument updatedBook = books.Update(query, update);

FindAndModify()

该方法会将查找到的文档进行修改,一般用于更新单个文档。也可以通过组合查询来匹配多个文档。

var jobs = database.GetCollection("jobs");

var query = Query.And(

Query.EQ("inprogress", false),

Query.EQ("name", "Biz report")

);

var sortBy = SortBy.Descending("priority");

var update = Update.

.Set("inprogress", true)

.Set("started", DateTime.UtcNow);

var result = jobs.FindAndModify(

query,

sortBy,

update,

true // return new document

);

var chosenJob = result.ModifiedDocument;

MapReduce()

Map/Reduce是一种从集合中聚合数据的方法。集合中的每个文档都会被传递到map函数,即emit,来产生中间值。而中间值会被传递到reduce函数进行聚合操作。

var map =

"function() {" +

" for (var key in this) {" +

" emit(key, { count : 1 });" +

" }" +

"}";

var reduce =

"function(key, emits) {" +

" total = 0;" +

" for (var i in emits) {" +

" total += emits[i].count;" +

" }" +

" return { count : total };" +

"}";

var mr = collection.MapReduce(map, reduce);

foreach (var document in mr.GetResults()) {

Console.WriteLine(document.ToJson());

}

其他的属性和方法

MongoCursor<TDocument>类:Find方法并不会立即的返回结果,而是返回一个能够枚举结果的游标;查询也不会立即的被发送到服务器上,而是在试图接收第一个结果时,才会被服务器处理。

枚举游标:通过foreach来枚举游标所指向的结果:

var query = Query.EQ("author", "Ernest Hemingway");

var cursor = books.Find(query);

foreach (var book in cursor) {

}

也可通过LINQ的拓展方法来枚举游标:

var query = Query.EQ("author", "Ernest Hemingway");

var cursor = books.Find(query);

var firstBook = cursor.FirstOrDefault();

var lastBook = cursor.LastOrDefault();

上面的方式,查询会被发送到服务器2次FirstOrDefault一次、LastOrDefault一次。

注意:当游标遍历完之后要记得释放(调用Dispose()方法)。

在枚举之前修改游标:在枚举游标之前可以修改游标的属性,有两种方式可以修改,一种是直接修改,另一种是通过Fluent接口设置属性。

// 跳过游标的前100条记录并只处理10条记录

var query = Query.EQ("status", "pending");

var cursor = tasks.Find(query);

cursor.Skip = 100;

cursor.Limit = 10;

foreach (var task in cursor) {

}

上面的实现也可以用下面的方式:

var query = Query.EQ("status", "pending");

foreach (var task in tasks.Find(query).SetSkip(100).SetLimit(10)) {

// do something with task

}

游标中可修改的属性:BatchSize、Fields 、Flags 、Limit 、Options 、SerializationOptions 、Skip、SlaveOk

其他的方法:Clone、Count、Explain、Size

WriteConcern类:新增、保存、更新和删除操作是否成功,查询操作可根据返回的查询结果判定(是否为空)。

Insert()返回WriteConcernResult其中比较重要的属性有:HasLastErrorMessage、LastErrorMessage、Response

Update()也返回WriteConcernResult其中DocumentsAffected表示被更新的文档数。UpdatedExisting表示是否有更新,其他的基本一致。

Save()和Remove()方法返回的WriteConcernResult与Update()一致。

为查找设置超时时间:collection.FindAll().SetMaxTime(TimeSpan.FromSeconds(1));当超过1秒钟,则查询会被中止。

批量操作(批量新增、更新、删除)

有两种方式可以进行批量操作,一种是对操作顺序执行,并返回第一个出错时的信息;一种是对操作并非执行,并返回所有出错的信息。

顺序执行的批量操作:

BulkWriteOperation bulk = collection.InitializeOrderedBulkOperation();

bulk.Insert(new BsonDocument("_id", 1));

bulk.Insert(new BsonDocument("_id", 2));

bulk.Insert(new BsonDocument("_id", 3));

bulk.Insert(new BsonDocument("_id", 4));

bulk.Find(Query.EQ("_id", 1)).Update(Update.Set("name", "wangdh1"));

bulk.Find(Query.EQ("_id", 2)).Remove();

bulk.Find(Query.EQ("_id", 3)).ReplaceOne(new BsonDocument("_id", 3).Add("name", "wangdh3"));

BulkWriteResult bulkResult = bulk.Execute();

并行执行的批量操作:

BulkWriteOperation bulk = collection.InitializeUnorderedBulkOperation();

bulk.Find(Query.EQ("_id", 1)).RemoveOne();

bulk.Find(Query.EQ("_id", 2)).RemoveOne();

BulkWriteResult bulkResult = bulk.Execute();

批量操作的返回值:BulkWriteResult

重要属性有:DeletedCount、InsertedCount、ModifiedCount、MatchedCount、ProcessedRequests分别表示删除、插入、更新、查找到的数量以及处理过程中产生的请求。

基础类:BSON命名空间

BSON类库是C#驱动的基础,处理的细节包括:I/O、序列化和BSON文档的内存对象模型。重要的BSON对象模型有:BsonType、BsonValue、BsonElement、BsonDocument、BsonArray.

BsonType:表示Bson的类型,是枚举类型。

BsonValue:Bson的value的抽象表示

BsonElement:是一个name/value表示的键值对类型

BsonDocument:是BsonElement(键值对)集合

创建内嵌的 BsonDocument:

BsonDocument nested = new BsonDocument {

{ "name", "John Doe" },

{ "address", new BsonDocument {

{ "street", "123 Main St." },

{ "city", "Centerville" },

{ "state", "PA" },

{ "zip", 12345}

}}

};

处理BsonDocument:既然BsonDocument是键值对集合,即可通过键名获取对应的值,再通过AsXXX方法将获取到的值转换为相应的类型。

BsonDocument book;

string author = book["author"].AsString;

DateTime publicationDate = book["publicationDate"].AsDateTime;

int pages = book["pages", -1].AsInt32;

BsonArray:Bson数组

时间: 2024-09-29 22:13:09

MongoDB学习比较-07 C#驱动操作MongoDB的相关文章

[转]MongoDB学习 C#驱动操作MongoDB

下载驱动 驱动的下载有两种方式:一种是在C#项目中通过NuGet进行安装,另一种是通过下面的链接:https://github.com/mongodb/mongo-csharp-driver/releases 直接下载msi进行安装或zip压缩包.不管哪种方式,其主要的目的都是获取两个dll文件:MongoDB.Bson.dll.MongoDB.Driver.dll.这是在程序中需要引用的两个类库文件. .NET版本要求 目前最新版的C#驱动是1.9.2,是在 .NET3.5的基础上构建的,所以

Nodejs学习笔记(二)--- 操作MongoDB数据库

最近看了一些关于mongodb的文章,然后就想知道nodeJS是怎么连接的所以我就尝试去了解了一波(这个菜鸟驿站这个网站还不错,虽然知识文档不是最新的,但是还是蛮好的: 顺便官网地址是这个哦:http://mongoosejs.com/docs/guide.html 好了,让我们来进入今天的主题: 首先来进入你项目的根目录下安装: npm install  mongoose 一直想用下这个数据的,最近终于得偿所愿.数据库的使用,我觉得首先是从增删改查开始,然后才去像更加复杂的地步去卖家首先如何去

c#驱动操作mongodb辅助类MongoDBHelper

using MongoDB.Bson; using MongoDB.Driver; using System; using System.Collections.Generic; /* https://docs.mongodb.com/manual/tutorial/update-documents/ https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/ https://docs.mongodb.com/manua

MongoDB学习笔记六:高级操作

[数据库命令]『命令的工作原理』MongoDB中的命令其实是作为一种特殊类型的查询来实现的,这些查询针对$cmd集合来执行.runCommand仅仅是接受命令文档,执行等价查询,因此,> db.runCommand({"drop" : "test"})这个drop调用实际上是这样的: db.$cmd.findOne({"drop" : "test"})当MongoDB服务器得到查询$cmd集合的请求时,会启动一套特殊的逻

在C#中使用官方驱动操作MongoDB

MongoDB的官方驱动下载地址:https://github.com/mongodb/mongo-csharp-driver/releases 目前最新的版本是2.10,支持.NET 4.5以上.由于我现在的程序还在.NET4.0上面构建,所以这里使用1.10.1版本. 添加引用 解压下载到的驱动,然后在我们的程序中添加引用: MongoDB.Bson.dll MongoDB.Driver.dll 然后在代码中添加Using: using MongoDB.Bson; using MongoDB

MongoDB学习笔记~关于官方驱动集成IQueryable之后的一些事

回到目录 关于官方驱动集成IQueryable之后的一些事,有好事也有坏事,好事就是它会将你的linq语句非常友好的翻译成MongoDB语句,而坏事就是有一些linq语句不会被翻译,不会被翻译的代价就是将整个结果集装到内存,然后进行linq to object的查询,效率自然是非常低的,呵呵. 好事 最新官方驱动中,添加了对IQueryable扩展方法的支持 public static IMongoQueryable<TDocument> AsQueryable<TDocument>

Mongodb学习总结-3(细说高级操作)

今天跟大家分享一下mongodb中比较好玩的知识,主要包括:聚合,游标. 一: 聚合 常见的聚合操作跟sql server一样,有:count,distinct,group,mapReduce. <1> count count是最简单,最容易,也是最常用的聚合工具,它的使用跟我们C#里面的count使用简直一模一样. <2> distinct 这个操作相信大家也是非常熟悉的,指定了谁,谁就不能重复,直接上图. <3> group 在mongodb里面做group操作有点

Mongodb学习总结-4(索引操作)

这些天项目改版,时间比较紧,博客也就没跟得上,还望大家见谅. 好,今天分享下mongodb中关于索引的基本操作,我们日常做开发都避免不了要对程序进行性能优化,而程序的操作无非就是CURD,通常我们 又会花费50%的时间在R上面,因为Read操作对用户来说是非常敏感的,处理不好就会被人唾弃,呵呵. 从算法上来说有5种经典的查找,具体的可以参见我的算法速成系列,这其中就包括我们今天所说的“索引查找”,如果大家对sqlserver比较了解 的话,相信索引查找能给我们带来什么样的性能提升吧. 我们首先插

mongodb学习之:文档操作

在上一章中有讲到文档的插入操作是用insert的方法.如果该集合不在该数据库中,mongodb会自动创建该集合并插入文档 用find的方法可以查找所有的集合数据 > db.maple.find() { "_id" : ObjectId("5a35d6278ef76f6d57aae92c"), "name" : "zhf" 也可以将数据定义为一个变量: document=({"name":"z