[转]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的基础上构建的,所以使用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:password@]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数组
[转]MongoDB学习 C#驱动操作MongoDB的更多相关文章
- MongoDB学习笔记:Python 操作MongoDB
MongoDB学习笔记:Python 操作MongoDB Pymongo 安装 安装pymongopip install pymongoPyMongo是驱动程序,使python程序能够使用Mong ...
- 使用MongoDB C#官方驱动操作MongoDB
想要在C#中使用MongoDB,首先得要有个MongoDB支持的C#版的驱动.C#版的驱动有很多种,如官方提供的,samus. 实现思路大都类似.这里我们先用官方提供的mongo-csharp-dri ...
- MongoDB学习-->命令行增删改查&JAVA驱动操作Mongodb
MongoDB 是一个基于分布式文件存储的数据库. 由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关 ...
- C#中使用官方驱动操作MongoDB
想要在C#中使用MongoDB,首先得要有个MongoDB支持的C#版的驱动.C#版的驱动有很多种,如官方提供的,samus. 实现思路大都类似.这里我们先用官方提供的mongo-csharp-dri ...
- [转载]在C#中使用官方驱动操作MongoDB
在C#中使用官方驱动操作MongoDB 8.1)下载安装 想要在C#中使用MongoDB,首先得要有个MongoDB支持的C#版的驱动.C#版的驱动有很多种,如官方提供的,samus. 实现思路大都类 ...
- MongoDB学习笔记一:MongoDB的下载和安装
MongoDB学习笔记一:MongoDB的下载和安装 趁着这几天比較空暇,准备学习一下MongoDB数据库.今天就简单的学习了一些MongoDB的下载和安装.并创建了存储MongoDB的数据仓库. 将 ...
- MongoDB快速入门学习笔记8 MongoDB的java驱动操作
import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.bson.D ...
- 在C#中使用官方驱动操作MongoDB
MongoDB的官方驱动下载地址:https://github.com/mongodb/mongo-csharp-driver/releases 目前最新的版本是2.10,支持.NET 4.5以上.由 ...
- golang学习之mgo操作mongodb
mgo是mongodb的golang驱动,测试代码: // mgotest project main.go package main import ( "fmt" "ti ...
随机推荐
- H
很爽的一局,打了70分钟,还刷新了我的最高击杀记录.打完出来一看居然是H局,第一次在H局里打出不错的表现诶.好像找人说一说,可惜并没有谁听,以前的朋友也不在了,还是算了,自己心里慢慢发霉去吧. 这局末 ...
- BZOJ4118 : [Wf2015]Window Manager
OPEN.CLOSE.RESIZE操作直接模拟即可. 对于MOVE,设$f_i$表示$i$号矩形的坐标,先无视边界通过DP求出每个矩形的坐标,再根据边界反向用第二次DP求出被移动矩形移动的真实距离,再 ...
- topcoder SRM 619 DIV2 GoodCompanyDivTwo
注意题目给的最后一句话,如果部门任何employee都做不同类型的工作,则这个部门是一个diverse,题目是计算department的diverse数 读起来感觉有点别扭,英语没学好的原因 int ...
- 【BZOJ】1100: [POI2007]对称轴osi
题意 给一个\(n(1 \le n \le 100000)\)个点不自交的多边形,求对称轴数目. 分析 将多边形表示成长度和角的形式(用有向面积来表示角也行),然后匹配. 题解 匹配可以用kmp或ma ...
- db2icrt创建实例,提示主机名无效
有这样一个现象,在DB2安装后,使用db2icrt 来创建实例时,提示主机名无效,提示如下: [root@centos-0 instance]# ./db2icrt -u db2inst1 db2 ...
- spring源码学习之路---深入AOP(终)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...
- 深入浅出 - Android系统移植与平台开发(四)- Android启动流程
作者:唐老师,华清远见嵌入式学院讲师. 一.Android init进程启动 还是从Linux的启动开始吧.Linux被bootloader加载到了内存之后,开始运行,在初始化完 Linux运行环境之 ...
- 在不知道json格式的情况下如何使用cjson进行解析
假设我们有一个json字符串,但是我们不知道这个json的组织方式,那么如何进行解析呢,下面就给一个小例子. 1.我们的json串如下: { "aStr": "aaaaa ...
- Nodejs Http发送post请求
Nodejs Http发送post请求 var http = require('http'); function epay(params) { console.log(" COME IN& ...
- 创建 maven 本地仓库
在 pom.xml 添加依赖包的时候,有时候会提示无法从 http://repo1.maven.org/maven2/ 获取的情况,这时可配置个本地仓库: 从网上下载 maven 仓库网站源码包 Ne ...