2

我有一个包含超过 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);
});

您会以更有效的方式进行此类操作吗?我的意思是如何避免加载游标的初始“查找”。现在有没有办法通过一个文档来做一个操作文档,知道所有文档都应该更新?

谢谢你的支持。

4

1 回答 1

1

您的问题启发了我创建一个Gist 来对解决您的问题的不同方法进行一些性能测试

以下是在 MongoDB 位于 localhost 的小型 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 个项目插入到新集合中。

虽然不包括在内,但我还使用 MapReduce 作为服务器端过滤器进行了测试,运行时间约为 19 秒。我本来希望类似地使用“聚合”作为服务器端过滤器,但它还没有输出到集合的选项。

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

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

于 2013-01-22T04:41:11.937 回答