Docs Home / Node.js Driver

Access Data From a Cursor从游标访问数据

Overview概述

Read operations that return multiple documents do not immediately return all values matching the query. Because a query can potentially match very large sets of documents, these operations return an object called a cursor, which references documents identified by the query. A cursor fetches documents in batches to reduce both memory consumption and network bandwidth usage. 返回多个文档的读取操作不会立即返回与查询匹配的所有值。因为查询可能会匹配非常大的文档集,所以这些操作会返回一个称为游标的对象,该对象引用由查询标识的文档。游标批量获取文档,以减少内存消耗和网络带宽使用。Cursors are highly configurable and offer multiple interaction paradigms for different use cases.游标具有高度的可配置性,并为不同的用例提供多种交互范式。

The following functions directly return cursors:

  • Collection.find()
  • Collection.aggregate()
  • Collection.listIndexes()
  • Collection.listSearchIndexes()
  • Db.aggregate()
  • Db.listCollections()

Other methods such as Collection.findOne() and Collection.watch() use cursors internally, and return the results of the operations instead of a cursor.其他方法,如Collection.findOne()Collection.watch(),在内部使用游标,并返回操作结果而不是游标。

Cursor Paradigms游标范式

You can use several different cursor paradigms to access data. Most cursor paradigms allow you to access query results one document at a time, abstracting away network and caching logic. However, since use cases differ, other paradigms offer different access patterns, like pulling all matching documents into a collection in process memory.您可以使用多种不同的游标范式来访问数据。大多数游标范式允许您一次访问一个文档的查询结果,从而抽象出网络和缓存逻辑。然而,由于用例不同,其他范式提供了不同的访问模式,比如将所有匹配的文档拉入进程内存中的集合。

Warning

Do not combine different cursor paradigms on a single cursor. Operations such as hasNext() and toArray() each predictably modify the original cursor. If you mix these calls on a single cursor, you may receive unexpected results.不要在单个游标上组合不同的游标范式。hasNext()toArray()等操作都会按预期修改原始游标。如果在单个游标上混合这些调用,可能会收到意外的结果。

Warning

Because asynchronous calls directly modify the cursor, executing asynchronous calls on a single cursor simultaneously can also cause undefined behavior. Always wait for the previous asynchronous operation to complete before running another.因为异步调用直接修改游标,所以同时对单个游标执行异步调用也可能导致未定义的行为。始终等待上一个异步操作完成,然后再运行另一个。

Note

When you reach the last result through iteration or through an at-once fetch, the cursor is exhausted, which means it ceases to respond to methods that access the results.当您通过迭代或一次性获取到达最后一个结果时,游标耗尽,这意味着它停止响应访问结果的方法。

Asynchronous Iteration异步迭代

Cursors implement the AsyncIterator interface, which allows you to use cursors in for await...of loops:游标实现了AsyncIterator接口,该接口允许您在for await...of循环中使用游标:

  const cursor = myColl.find({});
console.log("async");
for await (const doc of cursor) {
console.log(doc);
}

Manual Iteration手册迭代

You can use the hasNext() method to check if a cursor can retrieve more data, and then use the next() method to retrieve the subsequent element of the cursor:您可以使用hasNext()方法检查游标是否可以检索更多数据,然后使用next()方法检索游标的后续元素:

  const cursor = myColl.find({});

while (await cursor.hasNext()) {
console.log(await cursor.next());
}

Return an Array of All Documents返回所有文档的数组

For use cases that require all documents matched by a query to be held in memory at the same time, use the toArray() method. Note that large numbers of matched documents can cause performance issues or failures if the operation exceeds memory constraints. 对于要求查询匹配的所有文档同时保存在内存中的用例,请使用toArray()方法。请注意,如果操作超出内存限制,大量匹配的文档可能会导致性能问题或失败。Consider using the for await...of syntax to iterate through results rather than returning all documents at once.考虑使用for await...of语法用于迭代结果,而不是一次返回所有文档。

  const cursor = myColl.find({});
const allValues = await cursor.toArray();

Stream API

Cursors expose the stream() method to convert them to Node Readable Streams. Cursors公开了stream()方法,将它们转换为Node Readable Streams。These streams operate in Object Mode, which passes JavaScript objects rather than Buffers or Strings through the pipeline.这些流在对象模式下运行,该模式通过管道传递JavaScript对象,而不是缓冲区或字符串。

  const cursor = myColl.find({});
cursor.stream().on("data", doc => console.log(doc));

Event API

As Readable Streams, cursors also support the Event API's close, data, end, and readable events:作为可读流,游标还支持Event API的closedataendreadable事件:

  const cursor = myColl.find({});
event is fired once per document
cursor.on("data", data => console.log(data));

Cursor Utility Methods游标实用方法

Rewind解开

To reset a cursor to its initial position in the set of returned documents, use rewind().要将游标重置到返回文档集中的初始位置,请使用rewind()

  const cursor = myColl.find({});
const firstResult = await cursor.toArray();
console.log("First count: " + firstResult.length);
await cursor.rewind();
const secondResult = await cursor.toArray();
console.log("Second count: " + secondResult.length);

Close关闭

Cursors consume memory and network resources both in the client application and in the connected instance of MongoDB. Use close() to free up a cursor's resources in both the client application and the MongoDB Server, as shown in the following example:游标消耗客户端应用程序和MongoDB连接实例中的内存和网络资源。使用close()在客户端应用程序和MongoDB服务器中释放游标的资源,如下例所示:

  await cursor.close();

We recommend manually closing any non-exhausted cursors that your application no longer uses to prevent resource leaks.我们建议手册关闭应用程序不再使用的任何未耗尽的游标,以防止资源泄漏。

Tip

Explicit Resource Management显式资源管理

The Node.js driver natively supports explicit resource management for MongoClient, ClientSession, ChangeStreams, and cursors. This feature is experimental and subject to change. Node.js驱动程序原生支持MongoClientClientSessionChangeStreams和游标的显式资源管理。此功能是实验性的,可能会发生变化。To learn how to use explicit resource management, see the v6.9 Release Notes.要了解如何使用显式资源管理,请参阅v6.9发行说明

Abort中止

You can cancel cursor operations by using an abort signal. This can help you manage your resources by releasing memory and network resources used by the cursor if they're no longer needed.您可以使用中止信号取消游标操作。这可以通过释放游标使用的内存和网络资源(如果不再需要)来帮助您管理资源。

Note

This feature is experimental. Aborting a signal closes a connection, which might cause unnecessary connection reestablishment.此功能是实验性的。中止信号会关闭连接,这可能会导致不必要的连接重建。

You can pass the signal command to the following methods:您可以将signal(信号)命令传递给以下方法:

  • collection.find()
  • collection.findOne()
  • collection.aggregate()
  • collection.countDocuments()
  • db.listCollections()
  • db.command()

To use an abort signal, create an AbortController instance and extract the signal from the controller. 要使用中止信号,请创建AbortController实例并从控制器中提取signalIn this code example, the process listens for a SIGINT (Ctrl+C) to trigger the abort() method. 在这个代码示例中,进程监听SIGINTCtrl+C)以触发abort()方法。You can pass the signal option to the find() method to abort the cursor operation if the signal triggers, as shown in the following example:如果信号触发,您可以将signal选项传递给find()方法以中止游标操作,如下例所示:

  const controller = new AbortController();
const { signal } = controller;

process.on('SIGINT', () => controller.abort(new Error('^C pressed')));

try {
const cursor = myColl.find({}, { signal });
for await (const doc of cursor) {
console.log(doc);
}
} catch (error) {
if (error === signal.reason) {
console.error('Operation aborted:', error);
} else {
console.error('Unexpected error:', error);
}
}