在 MongoDB 中等待查询
Posted
技术标签:
【中文标题】在 MongoDB 中等待查询【英文标题】:Wait for a query in MongoDB 【发布时间】:2022-01-19 17:20:53 【问题描述】:我有这个用 Typescript 编写的异步方法来查询,使用 nodejs 驱动程序,一个 MongoDB;编译器指出“myConnectedClient”之前的“await”对这个表达式的类型没有影响;我很困惑:对聚合()的调用是异步的吗?所以,我必须等待吗?谢谢。
async findQuery<T>(
collection: string,
findParams: Query<T>,
sort: Sort<T>,
myConnectedClient: MongoClient
)
const firstResult = await myConnectedClient // the compiler indicates await is useless
.db("ZZZ_TEST_ALL")
.collection("my_collection_01")
.aggregate<string>([ $project: _id: 0, name: 1 ]);
firstResult.forEach((field) =>
console.log(`Field: $field`);
);
更新:我必须在 .aggregate() 调用之后添加 .toArray();但为什么?任何人都可以解释我的机制吗?聚合()没有回调并且不返回承诺? .toArray() 有替代品吗?谢谢。
// now await it's ok
const firstResult = await myConnectedClient
.db("ZZZ_TEST_ALL")
.collection("my_collection_01")
.aggregate<string>([ $project: _id: 0, name: 1 ]).toArray();
【问题讨论】:
【参考方案1】:Aggregate 是同步的并返回一个AggregationCursor。
游标有许多异步方法来检索实际数据:toArray、forEach 或简单的iterator
在第一个sn -p firstResult中是游标,所以不需要等待。 您使用 firstResult.forEach 来记录结果。它确实返回了承诺,但你忽略了它,这会咬你 - findQuery 返回的承诺将立即解决,而 forEach 将并行迭代结果。为了保持承诺链,你应该这样做
const firstResult = myConnectedClient.......;
return firstResult.forEach(......);
所以从findQuery
返回的承诺只有在 forEach 被解析时才会被解析,例如你完成了对结果的迭代。
在第二个“update”sn-p中,firstResult是数据,所以需要await从toArray()中获取。显式游标的等价物是:
const cursor = myConnectedClient.......;
const firstResult = await cursor.toArray();
【讨论】:
但是为什么 aggregate() 不是异步的?它从数据库(I/O)中检索数据,所以在我看来应该是异步的,对吧? 因为文档是这样说的。我的答案中第一个链接后面的最上面一行说:aggregate<T>(pipeline?: Document[], options?: AggregateOptions): AggregationCursor<T>
你看,它返回一个对象。异步函数总是返回一个 Promise。它是 javascript。单线程,做异步操作的唯一方法是将控制权交还给事件循环。
我认为您对瘦客户端的 I/O 操作感到困惑,例如文件 I/O、http、sql。 Mongo 略有不同。客户端相当厚实,它在启动时会打开许多到 mongo 实例的持久连接并管理池以方便数据传输。聚合不检索数据,但发送请求以在服务器上运行管道。 Cursor 有许多异步方法来实际检索数据,但我认为我已经在答案中提到了它。
我非常欣赏理解一切并基于这些知识构建软件的态度。这将是理想的。这种方法的根本缺陷是,在现实世界中,没有人知道一切。在某些时候,您需要划清界限并相信文档 - 如果它说它是这样工作的,测试表明它确实如此,所以它一定是它。
感谢 Alex 抽出宝贵时间回复。以上是关于在 MongoDB 中等待查询的主要内容,如果未能解决你的问题,请参考以下文章
连续迭代 mongodb 游标(在移动到下一个文档之前等待回调)