您好,登錄后才能下訂單哦!
在.NET Core中使用MongoDB中如何使用Filter語句檢索文檔,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
任何文檔都屬于集合,因此所有CRUD操作都是在單個集合范圍中完成的。若要從集合中檢索文檔,可以使用Find
, FindSync
,和FindAsync
等方法。
FindSync
和FindAsync
兩者都有兩個帶有三個參數的重載。FindSync
和FindAsync
很相似,只是FindSync
是同步的,并阻塞直到它的調用完成。FindSync
返回IAsyncCursor
,而FindAsync
返回一個IAsyncCursor
的任務.
MongoDB以批形式返回查詢結果,批處理大小不會超過BSON文檔的最大大小。從版本3.2開始,BSON文檔的最大大小為16 MB。最大文檔大小有助于確保單個文檔在傳輸過程中不能使用過多的RAM或過多的帶寬。此約束在將文檔添加到集合時也適用,但是為了存儲更大的文檔,MongoDB已經將GridFS API作為一項規定。對于大多數查詢,第一批將返回101個文檔或剛好超過1MB的文檔,隨后的批處理將為4MB。我們可以在驅動程序中通過設置FindOptions
的BatchSize
屬性來覆蓋默認的批大小,該屬性作為第二個參數傳遞給任何find
方法。所以基本上,游標是指向查詢結果集的指針。
默認情況下,服務器將在不活動10分鐘后或客戶端耗盡游標后自動關閉游標。若要重寫此行為,可以指定在查詢中使用FindOptions
類的NoCursorTimeout
屬性值設置為false
。但是,如果你這樣做您應該手動關閉游標或耗盡游標。
驅動程序中的這個IAsyncCursor
表示異步游標。要訪問文檔,我們需要手動迭代游標。
讓我們構建我們的第一個Read查詢,這個查詢返回我們數據庫中books
中的所有數據。更新MainAsync
方法如下:
static async Task Main(string[] args)
{
await TestFindAsync();
Console.ReadLine();
}
static async Task TestFindAsync()
{
var connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
var database = client.GetDatabase("bookstore");
var collection = database.GetCollection<BsonDocument>("books");
using IAsyncCursor<BsonDocument> cursor = await collection.FindAsync(new BsonDocument());
while (await cursor.MoveNextAsync())
{
IEnumerable<BsonDocument> batch = cursor.Current;
foreach (BsonDocument document in batch)
{
Console.WriteLine(document);
Console.WriteLine();
}
}
}
任何find方法的第一個重載都有3個參數:FilterDefinition
(用于定義查詢的篩選器)、一個可選的FindOptions
(用于指定查詢的選項(例如游標超時、批處理大小等)和一個可選的cancellationToken
。
在上面的代碼中,我們通過向方法傳遞一個空的BsonDocument
來指定一個空的過濾器定義。另一種編寫方法是使用FilterDefinition<BsonDocument>.Empty
來表示一個空的過濾器。有了空過濾器,我們基本上是告訴它返回給我們集合中的所有文檔。然后,我們迭代游標以成批獲取文檔(while循環中的MoveNextAsync
),并調用cursor.Current
獲取當前批中的文檔,然后將其打印出來。
運行上面的代碼應該可以為我們提供該集合中已有的所有文檔
{ "_id" : ObjectId("5f33630f9e7b20e7e29208f3"), "bookname" : ".net core3.1 with mongodb", "description" : "這是一本關于 在.net core3.1中使用mongodb進行開發的教程", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219b"), "bookname" : ".net core3.1 with mongodb1", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程1", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219c"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219d"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1ea"), "BookName" : ".net core3.1 with mongodb21", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程21", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1eb"), "BookName" : ".net core3.1 with mongodb22", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程22", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1ec"), "BookName" : ".net core3.1 with mongodb23", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程23", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
我們可以看到返回的數據跟我們在上一篇文章中添加的文檔基本一樣,除了多了一個_id
屬性,所有集合在這個字段上都有一個唯一的主索引,如果您在創建文檔時沒有提供主索引,那么MongoDB會默認提供一個主索引。它的類型是ObjectId
,這是在Bson規范中定義。
為了演示FindOptions
,我將添加一個將批大小限制為2的選項,該選項將顯示我們在控制臺中循環的批。使用以下內容更新代碼
static async Task Main(string[] args)
{
await TestFindAsync();
Console.ReadLine();
}
static async Task TestFindAsync()
{
var connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
var database = client.GetDatabase("bookstore");
var collection = database.GetCollection<BsonDocument>("books");
FilterDefinition<BsonDocument> filter = FilterDefinition<BsonDocument>.Empty;
FindOptions<BsonDocument> options = new FindOptions<BsonDocument> {
BatchSize = 2,
NoCursorTimeout = false
};
using IAsyncCursor<BsonDocument> cursor = await collection.FindAsync(filter,options);
var batch = 0;
while (await cursor.MoveNextAsync())
{
batch++;
Console.WriteLine($"Batch: {batch}");
IEnumerable<BsonDocument> documents = cursor.Current;
foreach (BsonDocument document in documents)
{
Console.WriteLine(document);
Console.WriteLine();
}
}
Console.WriteLine($"Total Batch: { batch}");
}
并運行它以獲得以下結果:
Batch: 1
{ "_id" : ObjectId("5f33630f9e7b20e7e29208f3"), "bookname" : ".net core3.1 with mongodb", "description" : "這是一本關于 在.net core3.1中使用mongodb進行開發的教程", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219b"), "bookname" : ".net core3.1 with mongodb1", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程1", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
Batch: 2
{ "_id" : ObjectId("5f3367482d2d59d358e1219c"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219d"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
Batch: 3
{ "_id" : ObjectId("5f33850d467bf3877966f1ea"), "BookName" : ".net core3.1 with mongodb21", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程21", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1eb"), "BookName" : ".net core3.1 with mongodb22", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程22", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
Batch: 4
{ "_id" : ObjectId("5f33850d467bf3877966f1ec"), "BookName" : ".net core3.1 with mongodb23", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程23", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
Total Batch: 4
我們還可以通過調用ToListAsync
或ForEachAsync
從光標中獲取所有文檔并將它們放入內存中,從而以更簡潔的方式編寫此代碼。在IAsyncCursor
上有擴展方法可以這么做。下面是一些代碼:
collection.FindSync(filter).ToList();
await collection.FindSync(filter).ToListAsync();
await collection.FindSync(filter).ForEachAsync(doc => Console.WriteLine());
collection.FindSync(filter).FirstOrDefault();
collection.FindSync(filter).FirstOrDefault();
await collection.FindSync(filter).FirstOrDefaultAsync();
從代碼角度看,這看起來既簡潔又簡短,但它所做的是強制所有文檔都保存在內存中。在某些情況下,這可能不太理想,當查詢結果很大時,游標很有用,我們可以通過調用MoveNextAsync
或MoveNext
來移動光標。
此方法與其對應方法相似,但它返回IFindFluent
接口。這是一個流暢的接口,它為我們提供了一些簡單的語法:Count
,Skip
,Sort
,和Limit
(關于這些,下篇文章中會有更多的介紹)。從IFindFluent
中我們也可以返回一個游標(通過調用ToCursor
或ToCursorAsync
或一個列表(通過調用ToList
或ToListAsync
)。通過下面的代碼,我們可以使用Find方法獲取所有文檔并將它們打印到控制臺
await collection.Find(FilterDefinition<BsonDocument>.Empty)
.ForEachAsync(doc => Console.WriteLine(doc));
結果
{ "_id" : ObjectId("5f33630f9e7b20e7e29208f3"), "bookname" : ".net core3.1 with mongodb", "description" : "這是一本關于 在.net core3.1中使用mongodb進行開發的教程", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219b"), "bookname" : ".net core3.1 with mongodb1", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程1", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219c"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f3367482d2d59d358e1219d"), "bookname" : ".net core3.1 with mongodb2", "description" : "這是一本關于在.net core3.1中使用mongodb進行開發的教程2", "tags" : [".net core", "mongodb"], "remark" : "C#是世界上最好的語言", "publishyear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1ea"), "BookName" : ".net core3.1 with mongodb21", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程21", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1eb"), "BookName" : ".net core3.1 with mongodb22", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程22", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
{ "_id" : ObjectId("5f33850d467bf3877966f1ec"), "BookName" : ".net core3.1 with mongodb23", "Description" : "這是一本關 于在.net core3.1中使用mongodb進行開發的教程23", "Tags" : [".net core", "mongodb"], "Remark" : "C#是世界上最好的語言", "PublishYear" : 2020 }
大多數情況下,我們不想檢索所有文檔,而是指定一個篩選器,它返回與特定篩選器匹配的文檔。現在讓我們看看為查詢指定篩選器的方法。
BsonDocument
或String
我們可以將BsonDocument定義為一個過濾器,查詢將找到與文檔中定義的字段相匹配的文檔。將以下代碼添加到您的方法中,并運行它以檢索description
為“這是一本關于在.net core3.1中使用mongodb進行開發的教程1”的書籍
var filter = new BsonDocument("description", "這是一本關于在.net core3.1中使用mongodb進行開發的教程1");
await collection.Find(filter).ForEachAsync(doc => Console.WriteLine(doc));
這樣只返回符合條件的一個文檔
var filter = new BsonDocument("description", "這是一本關于在.net core3.1中使用mongodb進行開發的教程1");
await collection.Find(filter).ForEachAsync(doc => Console.WriteLine(doc));
您可能會有些困惑,因為這些方法接受FilterDefinition
,但是我們給了它一個BsonDocument
,它沒有出異常。之所以會發生這種情況,是因為它被隱式轉換,而且我們也可以通過字符串進行轉換。要使用字符串,我們需要定義一個有效的JSON字符串來指定過濾器。我們可以使用下面的代碼對字符串執行上述相同的操作,仍然會得到相同的結果:
var filter= "{description:'這是一本關于在.net core3.1中使用mongodb進行開發的教程1'}";
await collection.Find(filter).ForEachAsync(doc => Console.WriteLine(doc));
我們也可以指定比較或邏輯運算符。例如,查找2020年出版的書。我們可以如下所示構建查詢:
var filter = new BsonDocument("publishyear", new BsonDocument("$eq", 2020));
或者使用字符串
var filter = "{ Age: {'$eq': 23}}";
我們所做的是為操作符添加一個標識符,在我們的例子中是$eq
。
您可以使用FilterDefinitionBuilder
,它是FilterDefinition
的構建器。它提供了一套方法來構建查詢,而Lt作為其中之一,指定了小于比較。因此,我們可以使用FilterDefinitionBuilder
定義過濾器,如下所示:
var filter = new FilterDefinitionBuilder<BsonDocument>().Lt("publishyear", 2020);
或者使用接受LINQ表達式的重載方法:
var filter = new FilterDefinitionBuilder<Book>().Lt( book => book.PublishYear, 2020);
此外,您還可以使用靜態Builders
類來構建過濾器定義,該類還具有用于構建其他內容的靜態幫助方法,如投影定義、排序定義和其他一些方法。
var filter = Builders<BsonDocument>.Filter.Lt("publishyear", 2020);
var filter = Builders<Book>.Filter.Lt(book => book.PublishYear, 2020);
驅動程序還為過濾器定義重載了3個操作符。這個and (&)
, or (|)
和not (!)
操作。例如,我們希望得到出版年份是2020年且描述信息為這是一本關于在.net core3.1中使用mongodb進行開發的教程1
的書籍信息,我們可以使用構建器幫助方法和&
重載操作符如下
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Eq("publishyear", 2020) & builder.Eq("description", "`這是一本關于在.net core3.1中使用mongodb進行開發的教程1");
最后一部分我們沒有討論的是這些方法的重載,這些方法采用LINQ表達式,當我們有一個強類型對象時,我們可以使用LINQ表達式構建一個過濾器查詢。假設我們想讓出版年份為2020,描述信息為這是一本關于在.net core3.1中使用mongodb進行開發的教程1
的書籍信息打印出他們。我們使用以下代碼:
var collection = database.GetCollection<Book>("books");
await collection.Find(book => book.PublishYear == 2020 && book.Description == "這是一本關于在.net core3.1中使用mongodb進行開發的教程1").ForEachAsync(doc => Console.WriteLine(doc));
我們將集合類型更改為Book
并運行以下代碼,我們將在控制臺上得到一個錯誤:
錯誤描述顯示_id
不匹配任何類型的字段或屬性。這是因為Book對象無法映射_id
字段從數據庫到“學生”類型的任何屬性。這是在我們創建文檔時自動添加的。讓我們通過在Book類中添加Bson類型的ID屬性。
internal class Book
{
public ObjectId Id { get; set; }
public string BookName { get; set; }
public string Description { get; set; }
public IEnumerable<string> Tags { get; set; }
public string Remark { get; set; }
public int PublishYear { get; set; }
}
并運行發現正常了。當然你也可以通過設置IgnoreExtraElement為true來規避這個問題
它只是起作用了。所以很多時候,你會想用表達式樹語法來構建您的查詢。在需要更多粒度的情況下,可以使用其他方法。
看完上述內容,你們掌握在.NET Core中使用MongoDB中如何使用Filter語句檢索文檔的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。