MongoDB在同一集合中复制和更新多个文档

时间:2016-07-22 05:54:03

标签: node.js mongodb mongoose mongodb-query aggregation-framework

我有大约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方法也很慢。 有没有更快的方法呢?

1 个答案:

答案 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); }