MongoDB Node.js的每个方法

我有一个数据存储在数据库中的数组。 当我查看数据是否已经存在时,即使使用limit(1),each()也会调用两次。 我不知道这里发生了什么

collection.find({ month: 'april' }).limit(1).count(function(err, result){ console.log('counter', result); }); collection.find({ month: 'april' }).limit(1).each(function(err, result){ console.log('each', result); }); collection.find({ month: 'april' }).limit(1).toArray(function(err, result){ console.log('toArray', result); }); 

此时,4月份确切的1个数据集已经存储在集合中。 上面的查询会产生这样的输出:

 count 1 each {...} each null toArray {...} 

在mongo shell中,我检查了count()和forEach()方法。 一切都按预期工作。 这是一个驱动问题吗? 我做错了什么?

这是预期的行为。 驱动程序返回循环中的项目,然后在最后返回null以指示没有剩余项目。 你也可以在驱动的例子中看到这个:

 // Find returns a Cursor, which is Enumerable. You can iterate: collection.find().each(function(err, item) { if(item != null) console.dir(item); }); 

如果您对这些细节感兴趣,可以查看each细节的源代码 :

 if(this.items.length > 0) { // Trampoline all the entries while(fn = loop(self, callback)) fn(self, callback); // Call each again 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返回nullitem的值变为null ),这使得if(item == null) return callback(null, null); 被执行。 正如你所看到的,这个callback函数是用null调用的,而且这是你可以在控制台中看到的null

这是需要的,因为MongoDB使用游标返回匹配的文档。 如果集合中有数百万个文档,并且运行find() ,则不会立即返回所有文档,因为您的内存不足。 相反,MongoDB使用游标遍历项目。 “对于大多数查询,第一批返回101文件或只是足够的文件超过1兆字节。” 因此, this.items.length成为第一批中的项目数,但这不一定是查询产生的文档总数。 这就是为什么当迭代文档并将this.items.length变为0时,MongoDB使用游标来检查是否有更多的匹配文档。 如果有,则加载下一批,否则返回null

如果您使用较大的限制,则更容易理解。 例如,在limit(100000)情况下,如果MongoDB立即返回所有100000个文档,则需要大量内存。 更不用说处理速度有多慢。 相反,MongoDB可以批量返回结果。 比方说,第一批包含101个文件。 然后this.items.length变成101,但这只是第一批的大小,而不是结果的总数。 当遍历结果,并且到达当前批处理中最后一个(本例中为102nd)后的下一个项目时,MongoDB使用游标检查是否有更多匹配的文档。 如果有,则下一批文档被加载,否则为null

但是您不必在代码中使用nextObject() ,您只需要像在MongoDB示例中那样检查null