2013-01-19 34 views
2

我有一个mongoDB集合,包含超过1000000个文档,我想用专用信息逐一更新每个文档(每个文档都有一个来自其他收藏)。如何使用MongoDB/NodeJS进行大规模随机更新

我目前使用的是获取集合中的所有数据的光标,我通过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); 
     }); 
    }); 
}); 

呼叫并行

“保存” 任务

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

感谢您的支持。

+1

您是否有理由在开始处理之前获取所有文档?为什么不只是遍历一个游标而不是将它们全部读入一个数组并迭代一个数组? –

+0

是的,我同意你的观点,但仍然需要在处理每个文档之前先加载光标。你有不同的例子吗? – Michael

+0

不是真的 - 文档将从服务器批量获取(一次默认为100个)。你迫使一次性提取所有文件。 –

回答

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个项目中。

虽然不包括在内,我也做了与MapReduce的测试用作跑在约19秒的服务器侧滤波器。我希望有类似地使用“聚合”作为服务器端过滤器,但它还没有选项输出到集合。

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

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

+0

Awsome,谢谢你的回答。它清楚地解释了所有选项,谢谢! – Michael