这是期望的行为。驱动程序在循环中返回项目,然后在结束时返回
null
表示没有剩余项目。你也可以在驱动程序的
示例中看到这一点:
collection.find().each(function(err, item) {
if(item != null) console.dir(item);
});
如果你对详情感兴趣,你可以查看每个源代码:
if(this.items.length > 0) {
while(fn = loop(self, callback)) fn(self, callback);
self.each(callback);
} else {
self.nextObject(function(err, item) {
if(err) {
self.state = Cursor.CLOSED;
return callback(utils.toError(err), item);
}
>> if(item == null) return callback(null, null); <<
callback(null, item);
self.each(callback);
})
}
在这段代码中,
each
使用
loop
遍历数组中的项 (
var doc = self.items.shift();
)。当
this.items.length
变为
0
时,执行 else 块。else 块尝试从游标获取下一个文档。如果没有更多文档,
nextObject
返回
null
(
item
的值变为
null
),这会导致执行
if(item == null) return callback(null, null);
。可以看到回调函数使用
null
被调用,而这个
null
就是你在控制台中看到的
null
。
这是必要的,因为MongoDB使用
游标返回匹配的文档。如果集合中有数百万个文档并且您运行
find()
,则不会立即返回所有文档,因为您将耗尽内存。相反,MongoDB使用游标迭代项目。 "对于大多数查询,第一批返回101个文档或足够超过1兆字节的文档。"因此,
this.items.length
成为第一批中存在的项目数量,但这不一定是查询结果的总文档数。这就是为什么当您遍历文档并且
this.items.length
变为0时,MongoDB使用游标检查是否存在更多匹配的文档。如果有,它加载下一批,否则返回
null
。
如果您使用大的限制,就更容易理解这个问题。例如,在
limit(100000)
的情况下,如果MongoDB立即返回所有100,000个文档,那么您将需要大量内存。更不用说处理速度会变得多么缓慢了。相反,MongoDB会分批次返回结果。假设第一批包含101个文档,则
this.items.length
就变成了101,但这仅是第一批的大小,而不是结果的总数。当您迭代结果并到达当前批次中的最后一个之后的下一项(在本例中为第102项)时,MongoDB使用游标来检查是否有更多匹配的文档。如果有,就会加载下一批文档,否则加载
null
。
但您不必在代码中烦恼于
nextObject()
,您只需要像MongoDB示例中那样检查
null
即可。
console.log
输出err
变量,以便查看第二次迭代时它是什么吗? - jraede