在 mongosh 中迭代游标 mongosh
db.collection.find()
方法将返回一个游标。要访问文档,需要迭代游标。但是,在 mongosh
中,如果未使用 var
关键字将返回的游标分配给变量,则游标会自动迭代多达 20 次 [1],最多可在结果中输出前 20 个文档。
以下示例描述了如何通过手动迭代游标,或使用迭代器索引以访问文档。
手动遍历游标
在 mongosh
中,使用 var
关键字将从 find()
方法返回的游标赋值给变量时,游标不会自动迭代。
可以在 shell 中调用游标变量来迭代多达 20 次 [1] 并打印匹配文档,如以下示例所示:
var myCursor = db.users.find( { type: 2 } ); myCursor
也可以使用游标方法 next()
访问文档,如下例所示:
var myCursor = db.users.find( { type: 2 } ); while (myCursor.hasNext()) { print(tojson(myCursor.next())); }
可以考虑使用 printjson()
辅助方法来替换 print(tojson())
,作为替代打印操作:
var myCursor = db.users.find( { type: 2 } ); while (myCursor.hasNext()) { printjson(myCursor.next()); }
可以使用游标方法 forEach()
来迭代游标并访问文档,如以下示例所示:
var myCursor = db.users.find( { type: 2 } ); myCursor.forEach(printjson);
有关游标方法的更多信息,请参阅 JavaScript 游标方法和驱动程序文档。
[1] | ( 1, 2 )您可以通过设置 DBQuery.shellBatchSize 属性对文档数量(默认值为 20 )进行更改。 |
迭代器索引
在 mongosh
中,可以使用 toArray()
方法遍历游标,并以数组形式返回文档,如下所示:
var myCursor = db.inventory.find( { type: 2 } ); var documentArray = myCursor.toArray(); var myDocument = documentArray[3];
toArray()
方法会将游标返回的所有文档加载到 RAM 中;toArray()
方法会耗尽游标。
此外,一些驱动程序使用游标上的索引(即cursor[index]
)。这是对首先调用 toArray()
方法,然后在结果数组上使用索引的更快捷方式。
考虑以下示例:
var myCursor = db.users.find( { type: 2 } ); var myDocument = myCursor[1];
myCursor[1]
等效于以下示例:
myCursor.toArray() [1];
游标行为
在会话中打开的游标
从 MongoDB 5.0 开始,在客户端会话中创建的游标将在以下情况下关闭:相应的服务器会话以 killSessions
命令结束、会话超时或客户端已用尽游标时。
默认情况下,服务器会话的超时时间为 30 分钟。要更改数值,请在启动 mongod
时设置 localLogicalSessionTimeoutMinutes
参数。
在会话外打开的游标
会话下未打开的游标将在 10 分钟不活动后或客户端耗尽游标后自动关闭。要重写 mongosh
中的这一行为,可以使用 cursor.noCursorTimeout()
方法:
var myCursor = db.users.find().noCursorTimeout();
设置 noCursorTimeout
选项后,必须使用 cursor.close()
手动关闭游标,或者用尽游标的结果。
有关设置 noCursorTimeout
选项的详细信息,请参阅驱动程序文档。
游标隔离
当游标返回文档时,其他操作可能会与查询交错进行。
游标批处理
MongoDB Server 分批次返回查询结果。批次中的数据量不会超过 BSON 文档的最大大小。要重写批次的默认大小,请参阅 batchSize()
和 limit()
。
find()
、aggregate()
、listIndexes
和 listCollections
类型的操作每批次最多返回 16 兆字节。batchSize()
可以执行较小的限制,不能执行较大的限制。
find()
默认情况下,aggregate()
操作的初始批次大小为 101 份文档。针对生成的游标发出的后续 getMore
操作没有默认批量大小,因此它们需满足 16 MB 消息大小的限制。
对于包含不带索引的排序操作的查询,服务器必须在返回任何结果之前将所有文档加载到内存中以执行排序。
当您遍历游标并到达返回批次的末尾时,如果有更多结果,cursor.next()
将执行 getMore operation
来检索下个批次。要查看在迭代游标时批次中还有多少文档,可以使用 objsLeftInBatch()
方法,如以下示例所示:
var myCursor = db.inventory.find(); var myFirstDocument = myCursor.hasNext() ? myCursor.next() : null; myCursor.objsLeftInBatch();
游标信息
db.serverStatus()
方法返回一份包含 metrics
字段的文档。metrics
字段包含一个 metrics.cursor
字段,后者包含以下信息:
自上次服务器重启以来超时的游标数量
打开的游标数量,其选项
DBQuery.Option.noTimeout
设置为防止在一段时间不活动后出现超时“固定”打开游标的数量
打开的游标总数
以下示例调用了 db.serverStatus()
方法,并访问了结果中的 metrics
字段,然后通过 metrics
字段访问 cursor
字段:
db.serverStatus().metrics.cursor
结果为以下文档:
{ "timedOut" : <number> "open" : { "noTimeout" : <number>, "pinned" : <number>, "total" : <number> } }