前言
此篇博文是 Mongdb 基础系列之一;
本文为作者的原创作品,转载需注明出处;
简介
The db.collection.find() method returns a
cursor
. To access the documents, you need to iterate the cursor. However, in the mongo shell, if the returned cursor is not assigned to a variable using the var keyword, then the cursor is automatically iterated up to 20 times [1] to print up to the first 20 documents in the results.
db.collection.find() 返回一个cursor
;你需要通过一个cursor
来访问文档;在 mongo shell 中,如果返回的 cursor 对象并没有赋值给任何一个局部变量,那么默认,该 cursor 将会执行 20 次,并输出前 20 个 documents;
本章,我们使用下面的测试用例,来对本章的内容进行讲解,
1 | db.inventory.insertMany([ |
手动的对 Cursor 进行遍历
直接打印 cursor
1 | > var myCursor = db.inventory.find({}) |
我们通过查询 inventory 中所有的 elements 元素返回一个 cursor,并将该 cursor 引用赋值给 myCursor 局部变量;通过直接输出 myCursor,mongo shell 会输出头 20 个 documents 元素,当然,因为我们的测试用例中总共就 5 个元素,所以,这里只会输出这 5 个元素;
1 | > myCursor |
使用 next() 方法迭代输出
你也可以使用与 cursor 的 next() 方法来遍历访问 documents,如下所述,
1 | var myCursor = db.inventory.find({}); |
输出结果,
1 | { |
注意,上述的输出方法 print(tojson(myCursor.next())) 可以直接替换为 printjson()
1 | var myCursor = db.inventory.find({}); |
使用 forEach() 方法输出
除了使用 next() 来进行输出以外,我们还可以使用 forEach() 方法来进行输出,
1 | > var myCursor = db.inventory.find({}) |
输出结果,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55{
"_id" : ObjectId("597704eecb568ef80824a9c9"),
"item" : "journal",
"qty" : 25,
"size" : {
"h" : 14,
"w" : 21,
"uom" : "cm"
},
"status" : "A"
}
{
"_id" : ObjectId("597704eecb568ef80824a9ca"),
"item" : "notebook",
"qty" : 50,
"size" : {
"h" : 8.5,
"w" : 11,
"uom" : "in"
},
"status" : "A"
}
{
"_id" : ObjectId("597704eecb568ef80824a9cb"),
"item" : "paper",
"qty" : 100,
"size" : {
"h" : 8.5,
"w" : 11,
"uom" : "in"
},
"status" : "D"
}
{
"_id" : ObjectId("597704eecb568ef80824a9cc"),
"item" : "planner",
"qty" : 75,
"size" : {
"h" : 22.85,
"w" : 30,
"uom" : "cm"
},
"status" : "D"
}
{
"_id" : ObjectId("597704eecb568ef80824a9cd"),
"item" : "postcard",
"qty" : 45,
"size" : {
"h" : 10,
"w" : 15.25,
"uom" : "cm"
},
"status" : "A"
}
References
See JavaScript cursor methods and your driver documentation for more information on cursor methods.
将 Cursor 转换成数组
在 mongo shell 中,可以使用 toArray() 方法遍历一个 cursor 并将相关的结果通过一个数组进行返回;看下面这个例子,如果我们想要快速的获取得到当前 cursor 所返回的 documents 的第四个元素,注意,第一个元素从下表 0 开始;
1 | > var myCursor = db.inventory.find({}) |
输出
1 | > myDocument |
额外的,某些 drivers 允许直接在 cursor 对象上使用 index 来快速查询某个下标所对应的 document,比如使用 cursor[index],这实际上是通过 toArray() 实现下标访问的一种快捷方法,下面的两种调用方式是等价的,
1 | > var myCursor = db.inventory.find({}) |
使用 toArray() 的方式,
1 | myCursor.toArray() [1]; |
Cursor 特性
关闭不活跃的 Cursor
默认情况下,在 10 分钟以后 MongoDB 将会自动关闭
不活跃的 Cursor 连接;如果要禁用这个行为,可以使用 cursor 方法 cursor.noCursorTimeout(),
1 | var myCursor = db.users.find().noCursorTimeout(); |
记住,一旦你设置了 noCursorTimeout,就记得一定要通过 cursor.close() 方法来手动关闭连接;
Cursor 隔离
当一个 cursor 正在返回 documents 的时候,其它的操作可能对正在返回的 documents 进行并发操作;比如当前我们所使用的是 MMAPv1 存储引擎,当在返回 documents 的同时对该文档进行写入操作(比如 udpate ),那么会导致一个 cursor 有可能对某个特定的 document 返回多次;如果解决这个问题,参考 snapshot mode
Cursor Batches
MongoDB Servers 以 batch 的方式返回查询的结果;batch 中数据的总大小不会超过 BSON document size 的最大值,也就是 16M;(注意,BSON Document size 这里有两层意思,一个是如果是单个文档,那么最大值不能超过这个数;如果是 query 的返回结果的 batch,那么这个 batch 的总大小也不能超过这个数 );可以通过 batchSize() 和 limit()方法来修改这个默认值;
New in version 3.4: Operations of type find(), aggregate(), listIndexes, and listCollections return a maximum of 16 megabytes per batch. batchSize() can enforce a smaller limit,
but not
a larger one.
注意,这里提到了,通过 batchSize() 方法只能讲 batch size 调小,没有办法增大;
For queries that include a sort operation without an
index
, the server mustload all the documents
in memory to perform the sort before returning any results.
这里提到了,如果在查询的过程中,有 sort 的操作,而查询的对象没有 index,那么将会把所有的 documents 全部加载进入内存中,进行排序操作;
当你遍历完当前的 cursor batch 以后,如果还有更多的数据,cursor.next() 会执行一个 getMore operation 去获取下一个 batch 的数据;如果要查看当前 batch 中还有多少个 documents 没有遍历,可以使用 objsLeftInBatch() 方法;看下面这个例子,
1 | > var myCursor = db.inventory.find({}) |
我们遍历了 myCursor 中的一个元素,并将其保存到 myFirstDocument 变量中,那么当前的 batch 中嗨剩下多少个元素呢?
1 | > myCursor.objsLeftInBatch(); |
Cursor 的当前状态信息
db.serverStatus() 将会返回一个文档,包含了一个 metrics 字段,该字段的内容包含了当前 MongoDB 实例的运行状态和使用情况;该 metrics 字段的内容中包含了一个 metrics.cursor 字段,包含了如下的信息,
- number of timed out cursors since the last server restart
自动服务启动以来,有多少个 cursors 超时了; - number of open cursors with the option DBQuery.Option.noTimeout set to prevent timeout after a period of inactivity
- number of “pinned” open cursors
- total number of open cursors
获取当前 cursor 的信息,
1 | > db.serverStatus().metrics.cursor |
将会输出如下的信息,
1 | { |