如何用MongoDB / NodeJS做大规模的随机更新

我有一个有100多万个文件的mongoDB集合,我想用一个专门的信息逐一更新每个文档(每个文档有一个来自其他集合的信息)。

目前我使用的是从集合中获取所有数据的游标,我通过Node.js的asynchronous模块更新了每条logging

获取所有文档:

inst.db.collection(association.collection, function(err, collection) { collection.find({}, {}, function(err, cursor) { cursor.toArray(function(err, items){ ...... ); }); }); 

更新每个文档:

 items.forEach(function(item) { // *** do some stuff with item, add field etc. tasks.push(function(nextTask) { inst.db.collection(association.collection, function(err, collection) { if (err) callback(err, null); collection.save(item, nextTask); }); }); }); 

并行调用“保存”任务

 async.parallel(tasks, function(err, results) { callback(err, results); }); 

何,你会以更有效的方式做这种types的操作吗? 我的意思是如何避免最初的“查找”加载游标。 现在有办法通过doc了解所有文档应该更新吗?

感谢您的支持。

你的问题激发了我创造一个Gist来做一些性能testing的不同方法来解决你的问题。

以下是在localhost上使用MongoDB的小型EC2实例上运行的结果。 testing场景是对100000个元素集合中的每个文档进行唯一操作。

  1. 108.661秒 – 使用find()。toArray一次拉入所有项目,然后用单独的“保存”调用replace文档。
  2. 99.645秒 – 使用find()。toArray一次拉入所有项目,然后用单独的“更新”调用更新文档。
  3. 74.553秒 – 在批处理大小= 10的情况下遍历游标(find()。each),然后使用单独的更新调用。
  4. 58.673秒 – 迭代游标(find()。each),batchSize = 10000,然后使用单独的更新调用。
  5. 4.727秒 – 使用batchSize = 10000对游标进行迭代,并且一次插入到一个新的集合中。

虽然没有包括在内,但我也用MapReduce做了一个testing,用作服务器端filter,运行时间约为19秒。 我希望有类似的使用“聚合”作为服务器端filter,但它还没有一个选项输出到集合。

底线的答案是,如果你能摆脱它,最快的select是通过游标从最初的集合中取出项目,在本地更新它们并以大块的forms将它们插入到新的集合中。 然后你可以换旧的新collections。

如果您需要保持数据库处于活动状态,那么最好的select是使用批量较大的游标,并更新文档。 “保存”调用比“更新”慢,因为它需要replace整个文档,并可能需要重新索引它。