如何使用MongoDB / NodeJS进行大规模随机更新

时间:2013-01-19 09:27:30

标签: node.js mongodb

我有一个包含1000000多个文档的mongoDB集合,我想用专用信息逐个更新每个文档(每个文档都有来自其他集合的信息)。

目前我正在使用一个游标来获取集合中的所有数据,并通过Node.js的异步模块更新每个记录

获取所有文档:

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);
});
你会以更有效的方式进行这种类型的操作吗?我的意思是如何避免加载游标的初始“查找”。现在是否可以通过doc了解所有文档应该更新的操作文档?

感谢您的支持。

1 个答案:

答案 0 :(得分:1)

你的问题激励我为你的问题创建Gist to do some performance testing不同的方法。

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

  1. 108.661秒 - 使用find()。toArray立即拉入所有项目,然后用单独的“保存”电话替换文档。
  2. 99.645秒 - 使用find()。toArray立即提取所有项目,然后使用单独的“更新”呼叫更新文档。
  3. 74.553秒 - 使用batchSize = 10迭代光标(find()。each),然后使用单独的更新调用。
  4. 58.673秒 - 使用batchSize = 10000迭代光标(find()。each),然后使用单独的更新调用。
  5. 4.727秒 - 使用batchSize = 10000迭代光标,并一次插入新的10000个项目。
  6. 虽然没有包含,但我也用MapReduce做了一个测试,用作服务器端过滤器,运行时间约为19秒。我本来希望类似地使用“聚合”作为服务器端过滤器,但它还没有输出到集合的选项。

    最重要的答案是,如果你可以逃脱它,最快的选择是通过游标从初始集合中提取项目,在本地更新它们并将它们插入到大块的新集合中。然后你可以用旧的交换新的集合。

    如果需要保持数据库处于活动状态,那么最好的选择是使用带有大型batchSize的游标,并更新文档。 “保存”调用比“更新”慢,因为它需要替换整个文档,并且可能还需要重新索引它。