在上篇文章我们介绍了一些驱动程序相关的基础知识,以及如何将文档插入到集合中。在这篇文章中,我们将学习如何从数据库中检索文档。

作者:依乐祝

译文地址:https://www.cnblogs.com/yilezhu/p/13520021.html

英文地址:https://www.codementor.io/@pmbanugo/working-with-mongodb-in-net-2-retrieving-mrlbeanm5

任何文档都属于集合,因此所有CRUD操作都是在单个集合范围中完成的。若要从集合中检索文档,可以使用Find, FindSync,和FindAsync等方法。

FindSync&FindAsync

FindSyncFindAsync两者都有两个带有三个参数的重载。FindSyncFindAsync很相似,只是FindSync是同步的,并阻塞直到它的调用完成。FindSync返回IAsyncCursor ,而FindAsync返回一个IAsyncCursor的任务.

什么是IAsyncCursor

MongoDB以批形式返回查询结果,批处理大小不会超过BSON文档的最大大小。从版本3.2开始,BSON文档的最大大小为16 MB。最大文档大小有助于确保单个文档在传输过程中不能使用过多的RAM或过多的带宽。此约束在将文档添加到集合时也适用,但是为了存储更大的文档,MongoDB已经将GridFS API作为一项规定。对于大多数查询,第一批将返回101个文档或刚好超过1MB的文档,随后的批处理将为4MB。我们可以在驱动程序中通过设置FindOptionsBatchSize 属性来覆盖默认的批大小,该属性作为第二个参数传递给任何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

我们还可以通过调用ToListAsyncForEachAsync从光标中获取所有文档并将它们放入内存中,从而以更简洁的方式编写此代码。在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();

从代码角度看,这看起来既简洁又简短,但它所做的是强制所有文档都保存在内存中。在某些情况下,这可能不太理想,当查询结果很大时,游标很有用,我们可以通过调用MoveNextAsyncMoveNext来移动光标。

Find

此方法与其对应方法相似,但它返回IFindFluent接口。这是一个流畅的接口,它为我们提供了一些简单的语法:Count ,Skip ,Sort,和Limit(关于这些,下篇文章中会有更多的介绍)。从IFindFluent中我们也可以返回一个游标(通过调用ToCursorToCursorAsync或一个列表(通过调用ToListToListAsync)。通过下面的代码,我们可以使用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 }

查找特定的文件

大多数情况下,我们不想检索所有文档,而是指定一个筛选器,它返回与特定筛选器匹配的文档。现在让我们看看为查询指定筛选器的方法。

使用BsonDocumentString

我们可以将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

您可以使用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表达式,当我们有一个强类型对象时,我们可以使用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来规避这个问题

它只是起作用了。所以很多时候,你会想用表达式树语法来构建您的查询。在需要更多粒度的情况下,可以使用其他方法。

在下一个教程中,我们将看到如何进行 projections, sort, skip, limit and sort. 。

在.NET Core中使用MongoDB明细教程(2):使用Filter语句检索文档的更多相关文章

  1. 在.NET Core中使用MongoDB明细教程(3):Skip, Sort, Limit, Projections

    到目前为止,我们已经讨论了创建文档, 检索文档,现在让我们来研究一下文档排序,指定要跳过或限制返回的文档数量,以及如何进行投影.此篇文章中的实例代码摘录自原文,未像前几篇文章一样进行实际代码的验证. ...

  2. 在.NET Core中使用MongoDB明细教程(1):驱动基础及文档插入

    MongoDB,被归类为NoSQL数据库,是一个以类JSON格式存储数据的面向文档的数据库系统.MongoDB在底层以名为bson的二进制编码格式表示JSON文档,MongoDB bson实现是轻量级 ...

  3. MongoDB 教程(七):插入文档、更新文档、删除文档

    MongoDB 插入文档 文档的数据结构和JSON基本一样. 所有存储在集合中的数据都是BSON格式 —— BSON是一种类json的二进制形式的存储格式,简称Binary JSON. MongoDB ...

  4. 在.Net Core中使用MongoDB的入门教程(二)

    在上一篇文章中,讲到了MongoDB在导入驱动.MongoDB的连接,数据的插入等. 在.Net Core中使用MongoDB的入门教程(一) 本篇文章将接着上篇文章进行介绍MongoDB在.Net ...

  5. 在.Net Core中使用MongoDB的入门教程(一)

    首先,我们在MongoDB的官方文档中看到,MongoDb的2.4以上的For .Net的驱动是支持.Net Core 2.0的. 所以,在我们安装好了MangoDB后,就可以开始MangoDB的.N ...

  6. Asp.Net Core中使用MongoDB的入门教程,控制台程序使用 MongoDB

    内容来源  https://blog.csdn.net/only_yu_yy/article/details/78882446 首先,创建一个.Net Core的控制台应用程序.然后使用NuGet导入 ...

  7. MongoDB中的映射,限制记录和记录拼排序 文档的插入查询更新删除操作

    映射 在 MongoDB 中,映射(Projection)指的是只选择文档中的必要数据,而非全部数据.如果文档有 5 个字段,而你只需要显示 3 个,则只需选择 3 个字段即可. find() 方法 ...

  8. Mongodb 笔记02 创建、更新和删除文档

    创建.更新和删除文档          1. 插入并保存: 1). 单条插入,insert : db.foo.insert({"bar":"baz"}) 2). ...

  9. 转:在 C# 中使用 P/Invoke 调用 Mupdf 函数库显示 PDF 文档

    在 C# 中使用 P/Invoke 调用 Mupdf 函数库显示 PDF 文档 一直以来,我都想为 PDF 补丁丁添加一个 PDF 渲染引擎.可是,目前并没有可以在 .NET 框架上运行的免费 PDF ...

随机推荐

  1. javascript中的设计模式之发布-订阅模式

    一.定义 又叫观察者模式,他定义对象间的依照那个一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将的到通知.在javascript中,我们一般用时间模型来替代传统的发布-订阅模式 二 ...

  2. 玩LOL间歇性卡顿(FPS突然降低又马上恢复)?Windows10间歇性卡顿?

    一..问题描述: LOL时:画面突然死掉,不能操作:FPS突然降低,从三位数降到两位数(150 -> 6).我最开始就是从LOL这里观测到的,因为游戏是卡顿最直观.最明显的表现.之后才发现不玩游 ...

  3. python如何支持并发?

    由于GIL(Global Interpreter Lock)的存在使得在同一时刻Python进程只能使用CPU的一个核心,也就是对应操作系统的一个 内核线程,对于一个Python web程序,如果有个 ...

  4. BuuCTF Web Writeup

    WarmUp index.php <html lang="en"> <head> <meta charset="UTF-8"> ...

  5. Numpy random函数

    import numpy as np # 生成一个随机数组 np.random.randint(0,6,3) # array([1, 1, 3]) # 生成一个随机数组(二维数组) np.random ...

  6. 【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!

    写在前面 在互联网应用中,高并发系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一.京东618.秒杀.抢购促销等,这些都是典型的大流量高并发场景.关于秒杀,小伙伴们可以参见我的另一篇 ...

  7. 再见了Antirez永远的Redis之神

    其实antirez(Redis作者)退出Redis维护一发布我就在很多咨询网站上面看到了,当时也没太多感慨. 今天比较有空想去看看霉霉Twitter的,然后看到了antirez,我就又一次回顾了他的退 ...

  8. Python Selenium 搭建Web UI自动化

    Python搭建UI自动化环境 下载Python3 Python官网 PyCharm 环境配置 安装Python 勾选Add Python to PATH,一直下一步. 验证:CMD输入Python ...

  9. AsyncTask被废弃了,换Coroutine吧

    本文主要是学习笔记,有版权问题还请告知删文 鸣谢:guolin@第一行代码(第三版) 你是否也在最近的代码中看见了 AsyncTask 被一条横杠划掉了 这表明--他要被Google放弃了 Googl ...

  10. Android 自定义组件,自定义LinearLayout,ListView等样式的组件

    今天讲的其实以前自己用过,就是在网上拿下来的把图片裁剪成圆形的方法,之前的随笔也介绍过的, 用法就是,在布局里写控件或者组件的时候得把从com开始到你写的那个类的所有路径写下来. 至于我们该怎么创建呢 ...