查询结果返回过程
使用find函数进行查询时,MongoDB并不是一次返回结果集中的所有文
档,而是以多条文档的形式分批来返回查询结果,返回的文档会缓存到内存中。
这种批量返回结果的好处是,一方面,它可以减少客户端对服务器连接
次数,从而减轻服务器的查询负担;另一方面,当查询结果集很大时,批量返
回结果的方式可以减少客户端的等待时间,提高数据的处理效率。
游标介绍及使用
在MongoDB中,提供了类似关系型数据的游标cursor对象,使用它
来遍历结果集中的数据。
针对游标,MongoDB提供了许多函数,主要包括
方法名 | 功能 | 方法名 | 功能 |
hasNext | 判断是否还有更多的文档 | sort | 对查询结果进行排序 |
next | 用来获取下一条文档 | objsLeftInBatch |
查看当前批次剩余的未被迭代
的文档数量
|
toArray | 将查询结果放到数组中 | addOption |
为游标设置辅助选项,修改游
标的默认行为
|
count | 获取结果集中总的文档数量 | hint | 为查询强制使用指定索引 |
limit | 限制结果返回数量 | explain | 用于获取查询执行过程报告 |
skip | 跳过指定数目的文档 | snapshot | 对查询结果使用快照 |
使用游标时,需要注意下面几个问题
- 当调用find函数时,shell并不立即查询数据库,而是等真正开始获取结果时才发送查询请求
- 游标对象的每个方法几乎都返回游标对象本身,这样就可以方便的进行链式函数调用
- MongoDB Shell中使用游标输出文档包含两种情况:
- 自动迭代 如果不将find函数返回的游标赋值给一个局部变量进行保存的话,默认情况下游标会自动迭代20次
- 手动迭代 将find函数返回的游标赋值给一个局部变量,然后使用游标对象提供的函数进行手动迭代
- 使用清空后的游标,进行迭代输出时,显示内容为空
游标的生命周期
一个游标从创建到被销毁的整个过程存在的时间,称为游标的生命周期,它
包括游标的创建、使用以及销毁三个阶段。
当客户端使用find函数向服务器端发起一次查询请求时,会在服务器端创
建一个游标,然后就可以使用游标函数来操作查询结果。
下面三种情况会让游标销毁:
- 游标遍历完成后,或者客户端主动发送终止消息
- 客户端保存的游标变量不在作用域内
- 在服务器端10分钟内未对游标进行操作
关于游标的生命周期,需要说明:
- 有时希望游标存在时间长一些,避免这种“超时销毁”的行为,可以使用addOption函数为游标添加noTimeout的选项:
var mycurosr = db.collection.find().addOption(DBQuery.Option.noTimeout);
- 使用serverStatus()函数可以查看当前系统的游标状态
db.serverStatus().metrics.cursor{
"timed0ut":<number>,
"open":{
"noTimeout":<number>,
"pinned":<number>,
"total":<number>
}
}
游标快照的介绍及使用
MongoDB的游标在整个生命周期中不具有隔离性(isolated),当查询结果
集很大且在查询结果集上执行数据更新操作时,可能会多次返回同一个文档。
游标可能会返回那些由于由于体积变大而被移动到集合末尾的文档,解决这
个问题的方法是对查询进行快照(snapshot)。其语法如下
db.collection.find().snapshot()
使用快照后,查询就会在_id索引上来遍历执行,这样就可以保证每个文档
只会被返回一次,从而保证获取结果的一致性。
游标实例
//连接数据库
db = connect("localhost:27017/test");
//清空测试集合
db.query_cursor.drop();
for (i=0;i<20;i++)
{
db.query_cursor.insert({index:i,text:"Hello MongoDB!"});
}
//测试用例
print("========游标的使用---基本使用========")
var cursor = db.query_cursor.find({},{_id:0,index:1 });
// 跳过前15个元素
cursor.skip(15);
while (cursor.hasNext())
{
var obj = cursor.next();
print(tojson(obj));
var left = cursor.objsLeftInBatch();
print("Left in bash:",left);
}
print("========游标---toArray函数的使用========")
/*
函数原型:db.collection.find().toArray()
*/
var documentArray = db.query_cursor.find().toArray()
if (documentArray.length > 10)
{
var obj = documentArray[10];
printjson(obj)
}
print("========游标的使用---forEach函数的使用========")
/*
函数原型:db.collection.find().forEach(<function>)
*/
var cursor = db.query_cursor.find()
cursor.forEach( function(temp)
{
if (temp.index ==10)
{
print("test.index: " + temp.index+
" test.obj: " + temp.text )
}
})
print("========游标的使用---查看系统游标状态========")
var cursor_status = db.serverStatus().metrics.cursor
printjson(cursor_status)
运行结果如下:
C:\>mongo --quiet query_cursor.js
========游标的使用---基本使用========
{ "index" : 15 }
Left in bash: 4
{ "index" : 16 }
Left in bash: 3
{ "index" : 17 }
Left in bash: 2
{ "index" : 18 }
Left in bash: 1
{ "index" : 19 }
Left in bash: 0
========游标---toArray函数的使用========
{
"_id" : ObjectId("56e95db157f9114c1ae54c93"),
"index" : 10,
"text" : "Hello MongoDB!"
}
========游标的使用---forEach函数的使用========
test.index: 10 test.obj: Hello MongoDB!
========游标的使用---查看系统游标状态========
{
"timedOut" : NumberLong(0),
"open" : {
"noTimeout" : NumberLong(0),
"pinned" : NumberLong(0),
"total" : NumberLong(0)
}
}