[转]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 ...
随机推荐
- TCP/IP详解2 学习笔记---mbuf
1,mbuf就是存储要发送数据的memery buf,类似于skb_buf.不过结构比较简单. /* header at beginning of each mbuf: */ 这个结构用来描述mbuf ...
- Regionals 2012 :: Chengdu
题目连接 排行榜 A和I都是签到题 按位BFS K Yet Another Multiple Problem 题意:给一些可以用的数字,求最小的数,它由特定的数字组成且是n的倍数 分析:暴力枚举不可行 ...
- jQuery入门第二天
3种选择器:元素选择器:$("button").class选择器:$(".btn").id选择器:$("#target1"). <sc ...
- java基础知识复习
String http://blog.csdn.net/uyu2yiyi/article/details/6275808 1. 首先String不属于8种基本数据类型,String是一个对象. 因为 ...
- 51nod p1175 区间中第K大的数
1175 区间中第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 一个长度为N的整数序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有 ...
- Issues I encountered when building Windows Store apps on a new laptop
I took over my beloved wives samsung ativ book 9 recently as her first job granted her a brandnew su ...
- android 百度地图 通过剪裁图片添加 Marker
初始化百度地图: private void initViews() { mMapView = (MapView) findViewById(R.id.bmapView); mBaiduMap = mM ...
- To Do List
妈呀...发现不发博文公布自己要学的东西压力少太多了.......... 然后就会变得颓废..................... 求大家监督QAQ....To Do List是近3天左右目标,3天 ...
- IEqualityComparer<T>
在linq中使用union和distinct都不起作用,结果发现必须传入一个实现了IEqualityComparer<T>的比较器 public class CompareUser : I ...
- 解决clang: error: no such file or directory: such file or directory:的问题
一,详细问题描述 clang: error: no such file or directory: 'xxx/src/GGBaCollectionViewCell.m' clang: error: n ...