【发布时间】:2016-06-23 17:23:13
【问题描述】:
向超过 1 亿个 mongodb 文档添加新字段的最快和最安全的策略是什么?
背景
在 3 节点副本集中使用 mongodb 3.0
我们正在添加一个新字段 (post_hour),它基于当前文档中另一个字段 (post_time) 中的数据。 post_hour 字段是 post_time 到小时的截断版本。
【问题讨论】:
标签: mongodb mongodb-query pymongo
向超过 1 亿个 mongodb 文档添加新字段的最快和最安全的策略是什么?
背景
在 3 节点副本集中使用 mongodb 3.0
我们正在添加一个新字段 (post_hour),它基于当前文档中另一个字段 (post_time) 中的数据。 post_hour 字段是 post_time 到小时的截断版本。
【问题讨论】:
标签: mongodb mongodb-query pymongo
我遇到了类似的情况,我创建了一个脚本来更新大约 2500 万个文档,并且需要花费大量时间来更新所有文档。为了提高性能,我将更新后的文档一一插入到新集合中并重命名了新集合。这种方法很有帮助,因为我是在插入文档而不是更新它们(“插入”操作比“更新”操作快)。
这里是示例脚本(我没有测试过):
/*This method returns postHour*/
function convertPostTimeToPostHour(postTime){
}
var totalCount = db.person.count();
var chunkSize = 1000;
var chunkCount = totalCount / chunkSize;
offset = 0;
for(index = 0; index<chunkCount; index++){
personList = db.persons.find().skip(offset).limit(chunkSize);
personList.forEach(function (person) {
newPerson = person;
newPerson.post_hour = convertPostTimeToPostHour(person.post_time);
db.personsNew.insert(newPerson); // This will insert the record in a new collection
});
offset += chunkSize;
}
当上面编写的脚本将被执行时,新集合'personNew'将具有字段'post_hour'设置的更新记录。
如果现有集合有任何索引,您需要在新集合中重新创建它们。
创建索引后,您可以将集合名称“person”重命名为“personOld”,将“personNew”重命名为“person”。
【讨论】:
snapshot 将允许防止查询结果中的重复(因为我们正在扩展大小) - 如果发生任何问题,可以将其删除。
请在下面找到 'a1' 是集合名称的 mongo shell 脚本:
var documentLimit = 1000;
var docCount = db.a1.find({
post_hour : {
$exists : false
}
}).count();
var chunks = docCount / documentLimit;
for (var i = 0; i <= chunks; i++) {
db.a1.find({
post_hour : {
$exists : false
}
}).snapshot()
.limit(documentLimit)
.forEach(function (doc) {
doc.post_hour = 12; // put your transformation here
// db.a1.save(doc); // uncomment this line to save data
// you can also specify write concern here
printjson(doc); // comment this line to avoid polution of shell output
// this is just for test purposes
});
}
您可以使用参数,但由于批量是在 1000 个记录块中执行,这看起来是最佳的。
【讨论】: