我们之前的数据模型假设某个字段,我们称之为field
缺乏想象力,可能包含多个值,因此我们将其建模为数组。
初始模型:
{
field: ['val1]
}
然后我们意识到(后来有1000万个文档)情况并非如此,并改为:
{
field: 'val1;
}
我认为迁移到新模型会很简单,但显然不是。
我试过了:
db.collection.update({},{$rename: {"field.0": 'newField'}})
但它抱怨数组元素不能在$rename
运算符的第一位使用。
据我所知,在更新操作中,您无法将字段值分配给另一个,我调查了聚合框架,但我无法找到方法。
$out
运算符编辑文档来完成我想要的吗?我也试过foreach
,但是死得很慢:
db.coll.find({"field":{$exists:true}}).snapshot().forEach(function(doc)
{
doc.newField = doc.field[0];
delete doc.field;
db.coll.save(doc);
});
我使用bash脚本对其进行了并行化,并且我能够达到大约200个更新/秒,这意味着10.000.000/(200*60*60)= 14h
,需要等待一段时间,而不考虑我使用bash脚本处理的超时错误但是浪费更多时间。
所以现在我问,批量操作或聚合框架是否有可能加速这个过程?
答案 0 :(得分:1)
将进行批量操作,因为它们允许执行批量更新操作,这些操作只是服务器顶部的抽象,以便轻松构建批量操作,从而简化您的更新。随着 bulk API
批量发送写入操作,您可以获得超过大型集合的性能提升,甚至更好,它可以为您提供有关成功和失败的真实反馈。在批量更新中,您将以1000个批次的形式将操作发送到服务器,这样可以提供更好的性能,因为您不是每次向服务器发送每个请求,而是每1000次请求中只有一次:
var bulk = db.collection.initializeOrderedBulkOp(),
counter = 0;
db.collection.find({"field": { "$exists": true, "$type": 4 }}).forEach(function(doc) {
var updatedVal = doc.field[0];
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "field": updatedVal }
});
counter++;
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
bulk = db.collection.initializeUnorderedBulkOp();
}
});
// Clean up queues
if (counter % 1000 != 0) { bulk.execute(); }