標籤:
下載驅動
驅動的下載有兩種方式:一種是在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數組
MongoDB學習比較-07 C#驅動操作MongoDB