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

作者:依乐祝

译文地址: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. 题解 洛谷 P3210 【[HNOI2010]取石头游戏】

    考虑到先手和后手都使用最优策略,所以可以像对抗搜索一样,设 \(val\) 为先手收益减去后手收益的值.那么先手想让 \(val\) 尽可能大,后手想让 \(val\) 尽可能小. 继续分析题目性质, ...

  2. ISE第三方编辑器的使用

    刚开始使用ISE时候感觉ISE自带的编辑器并没有什么难用的,但是在看到了小梅哥的视频教学中那样行云流水般的操作让我心动不已,由此找到了相关的编辑器.为了以后看着方便直接摘取了前人的经验在我自己的博客中 ...

  3. 解决react使用antd table组件固定表头后,表头和表体列不对齐以及配置fixed固定左右侧后行高度不对齐

    一.固定表头后表体列和表头不对齐 此问题可能在antd3.24.0版本之前都存在,反正3.16.2版本是存在这个问题的,如果是3.24.0之前的版本估计只能通过修改css样式解决. 按照官网说的: 1 ...

  4. 深入浅出系列第一篇(设计模式之单一职责原则)——从纯小白到Java开发的坎坷经历

    各位看官大大们,晚上好.好久不见,我想死你们了... 先说说写这个系列文章的背景: 工作了这么久了,每天都忙着写业务,好久没有好好静下心来好好总结总结了.正好这段时间公司组织设计模式的分享分,所以我才 ...

  5. yum下载软件包

    方法一: downloadonly插件有一个yum的插件叫做downloadonly,就是只下载不安装的意思.1. 安装插件yum install yum-download2. 下载yum updat ...

  6. makefile for Linux纯小白版

    某大佬曾说过: 不会makefile,不要说你会linux,因为makefile是合格程序员的必经之路 首先你要有个vi或者emacs 之类的编辑器 编写几个程序 test1.c #include&l ...

  7. PD快充和QC快充

    参考链接:https://zhidao.baidu.com/question/246420719602653564.html PD快充协议 PD即USB Power Delivery Specific ...

  8. 7月30日 举办专注于微服务的.NET Conf Focus

    2020 年 7 月 30 日, 由.NET基金会和微软 将举办一个在线和为期一天的活动,包括 微软 .NET 团队的演讲者以及社区的演讲者.本次在线大会 专注.NET框架构建微服务,演讲者分享构建和 ...

  9. SUM and COUNT -- SQLZOO

    SUM and COUNT 注意:where语句中对表示条件的需要用单引号, 下面的译文使用的是有道翻译如有不正确,请直接投诉有道 01.Show the total population of th ...

  10. PHP nl_langinfo() 函数

    定义和用法 nl_langinfo() 函数返回指定的本地信息. 注释:该函数无法在 Windows 平台上工作. 提示:与返回所有本地格式化信息的 localeconv() 函数不同,nl_lang ...