写在前面
mongoose
在github上是一个很受欢迎的开源项目,作为加强版的mongo node driver,有很多优点,但是无奈文档不怎么全面,下面是一些关于mongoose cursor
的用法总结
环境
- node 6.9.1
- mongoose 4.11.0 (如果可能,尽量用新版,开源的东西,你懂的)
cursor基础
cursor生命周期
cursor就是mongodb查询游标,利用它可以返回所有的查询结果,可以一次性返回,可以分批返回。
默认情况下,查询游标的生存周期是10分钟,如果在这期间,cursor耗尽(已经返回了所有结果),mongo server也会关闭这个cursor。cursor有选项noTimeout,可以阻止这个默认行为,如果使用了这个选项,就必须要手动关闭cursor或者是药最终有能力耗尽这个cursor。
cursor隔离性
cursor使用过程当中肯定存在一些其他的操作会影响正在查询的数据,如果使用的饰mmapv1存储引擎,在某些情况下,会导致同一个document返回多次的情况,关于这一些,官方文档有详细的说明,建议大家早日更换wt
As a cursor returns documents other operations may interleave with the query: with MMAPv1 storage engine, if some of these operations are updates that cause the document to move (in the case of a table scan, caused by document growth) or that change the indexed field on the index used by the query; then the cursor will return the same document more than once.
cursor batch
使用游标获取数据的时候,数据是分批返回的。每一批数据不能超过maximum BSON document size,默认情况下,第一批数据返回101条数据或者不超过1MB的数据,之后每次返回4M数据。可以手动设定batch size
mongoose中使用cusror
查询
1 | var cursor = UserModel.find({name: 'kivi'}).cursor({batchSize: 100}); |
一开始我也想着应该有什么方法能一次性拿到一个batch的数据,最终发现数据还是会一条一条的过来
Batch sizes are just for performance optimisation and will not give you a 50 object chunk.
You will still have to process each doc individually.
聚合
正常情况下,这么用是没问题的1
2
3
4
5
6
7
8
9var cursor = model.aggregate(parameters).cursor({ batchSize: 1000 }).exec();
cursor.on('data', function (doc) {
// do something
});
cursor.on('end', function (doc) {
console.log('cursor exausted';
});
cursor.on('error', function (err) {
});
但是上面的写法有的时候cursor是null,这是mongoose的一个bug,连接没有完全建立的时候就会出现这种情况
It’s unfortunately a bug with the first way we implemented aggregation cursors - cursor will be undefined if the model’s underlying connection has not successfully connected. That’s what the async option for agg cursors is for:
model.aggregate(parameters).cursor({ batchSize: 1000, async: true }).exec(function(error, cursor) {
// Can now use cursor
});
The reason why it needs to be async is that mongoose may need to wait for the connection to mongodb to be established before it can actually return the cursor.
所以下面的async参数非常有意义
1 | UserModel |
以上是mongoose cursor使用的两个最基本的场景,以后会补充更多关于cursor更加丰富的用法