MongoDB 中游标(Cursor)

Aug 29, 2018 阅读(5166)

标签: MongoDB

引入

db.collection.find()方法返回一个游标结果,访问文档需要遍历这个游标值。 在mongo shell 中返回的游标值没有赋值给 var 关键字定义的变量时会自动遍历20次并打印这头20条的文档结果,如果返回的游标值赋值给了var 关键字定义的变量时不会自动遍历这个游标结果。

Tips:这里的游标返回默认结果数20可以通过 DBQuery.shellBatchSize 来修改。

手动(遍历)迭代游标

  • 运行游标结果,迭代(遍历)并打印20条匹配到的文档:

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);


迭代索引

在mongo shell 中可以使用游标的 toArray() 方法迭代遍历游标结果,并将结果集放在一个数组中返回。

var myCursor = db.inventory.find( { type: 2 } );
var documentArray = myCursor.toArray();
var myDocument = documentArray[3];

toArray() 方法会将游标中的所有文档加载到内存中,同时耗尽这个游标。


有部分Mongodb数据库驱动提供根据cursor索引位置获取文档数据的方法。(例如:cursor[index]). 这是先调用toArray()方法再用索引获取数组中元素的简写。

var myCursor = db.users.find( { type: 2 } );
var myDocument = myCursor[1];
// 这里的 myCursor[1] 等价与下面的这行
myCursor.toArray() [1];


游标行为

  • 关闭不活动的Cursor

默认情况下,服务器会自动关闭超过10分钟活跃的或客户端已耗尽的游标。想不使用这个默认行为在 mongo shell 中可以使用ursor.noCursorTimeout()方法:

var myCursor = db.users.find().noCursorTimeout();

设定noCursorTimeout这个选项后,你必须通过cursor.close()方法手动关闭, 或者耗尽这个游标。


  • 游标隔离

当游标返回文档时,其他操作可能与查询交织。对于MMAPv1存储引擎,如果文档发生更改,对文档的写入操作可能导致游标多次返回文档。若要处理此情况,请参阅游标快照信息。


  • 游标批处理

MongoDB服务器将结果打包返回. 数据包的大小不能超过默认BOSN文档大小(16M)maximum BSON document size。 可以通过batchSize()和limit()来修改返回结果集。

3.4 新版本 find(), aggregate(), listIndexes, 和listCollections每批返回最大16M的数据。batchSize()可以设置一个更小的限制, 而不是最大的限制。

find()和aggregate() 默认初始集合文档数量是101。后来的getMore操作,没有默认集合文档数量限制, 只是有16M最大字节数限制。


Tips:有sort排序没有索引的查询操作时, 返回结果前, 服务器必须将全部数据加载进内存中来实现排序。


遍历结果集到达返回数据的末尾时, 如果有更多的数据, 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 选项防止超时打开的游标数;

  • pinned 打开的游标数量;

  • 打开游标的总数量;

db.serverStatus().metrics.cursor

结果显示

{
   "timedOut" : <number>
   "open" : {
      "noTimeout" : <number>,
      "pinned" : <number>,
      "total" : <number>
   }
}


译自: https://docs.mongodb.com/manual/tutorial/iterate-a-cursor/

游标方法参考: https://docs.mongodb.com/manual/reference/method/#js-query-cursor-methods




MongoDB学习园