我有大约40000条记录我需要更新一个planId字段并将记录复制到同一个集合中。 现在我正在使用基本的
linkModel.find({},callback) & linkModel.insertMany([linksArray],callback)
但这需要花费很多时间。
我尝试了聚合,但$out
运算符替换了现有的集合,而我想更新它而不是替换。
到目前为止我尝试过的三个步骤:
db.links.aggregate([ { $match: { planId: ObjectId("5732f50a6886e5421259e823") } }, { $out: "temp" } ]);
db.temp.updateMany({planId:ObjectId("5732f50a6886e5421259e823")},{$set:{planId:ObjectId("5791b25f203b5e92316e60c3")}})
db.temp.copyTo("links")
,
但即使是copyTo方法也很慢。 有没有更快的方法呢?
答案 0 :(得分:0)
利用 Bulk API
进行批量更新。它们提供了更好的性能,因为您将以1000个批量发送操作到服务器,这样做效率更高,因为您没有向服务器发送每个请求,而是每1000个请求中只发送一次。
以下演示了此方法,第一个示例使用MongoDB版本>= 2.6 and < 3.2
中提供的批量API。它更新所有
通过将所有Cost
字段更改为浮动值字段来收集集合中的文档:
var bulk = db.links.initializeUnorderedBulkOp(),
counter = 0;
db.links.find({ planId: ObjectId("5732f50a6886e5421259e823") })
.snapshot().forEach(function (doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "planId": ObjectId("5791b25f203b5e92316e60c3") }
});
counter++;
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations
// re-initialize every 1000 update statements
bulk = db.links.initializeUnorderedBulkOp();
}
})
// Clean up remaining operations in queue
if (counter % 1000 != 0) { bulk.execute(); }
下一个示例适用于自deprecated Bulk API
以来的新MongoDB版本3.2,并使用 bulkWrite()
提供了一套更新的api 强>
它使用与上面相同的游标,但使用相同的forEach()
游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组。因为写入命令可以接受不超过1000次操作,所以您需要将操作分组以进行最多1000次操作,并在循环达到1000次迭代时重新初始化数组:
var cursor = db.links.find({ planId: ObjectId("5732f50a6886e5421259e823") }).snapshot(),
bulkUpdateOps = [];
cursor.forEach(function(doc){
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "planId": ObjectId("5791b25f203b5e92316e60c3") } }
}
});
if (bulkUpdateOps.length == 1000) {
db.links.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.links.bulkWrite(bulkUpdateOps); }