Stid Zhang
Stid Zhang

Reputation: 47

MongoDB: Update Multiple Documents with Certain Criteria

The following is how it looks like in the collection in my database:

{
    row_num: 1,
    value: 15
}
{
    row_num: 2,
    value: 74
}
...

Right now I have the following updated JSON file:

{
    row_num: 1,
    value: 16
}
{
    row_num: 2,
    value: 28
}
...

which maps one to one to the data in MongoDB. My question is that is it possible to use MongoDB syntax to update the value in every document in one single row instead of having a loop inside my script to update it?

Upvotes: 1

Views: 496

Answers (1)

chridam
chridam

Reputation: 103355

It's possible when you use the Bulk() API to do the update instead of sending an update request for each document in the JSON array with a loop. This also has improved performance in that you will be sending the operations to the server in batches (for example, say a batch size of 500) making your updates more efficient and quicker.

The following demonstrates this approach, the first example uses the Bulk() API available in MongoDB versions >= 2.6 and < 3.2. It updates all the matched documents in the collection from a given array by modifying the existing value field to the one in the JSON:

var updatedJsonArray = [
    { "row_num": 1, "value": 16 },
    { "row_num": 2, "value": 28 },
    { "row_num": 3, "value": 43 },
    ...
    { "row_num": 15478, "value": 9 }
]

MongoDB versions >= 2.6 and < 3.2:

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

updatedJsonArray.forEach(function (doc) {    
    bulk.find({ "row_num": doc.row_num }).updateOne({ 
        "$set": { "value": doc.value }
    });

    counter++;
    if (counter % 500 === 0) {
        // Execute per 500 operations
        bulk.execute(); 
        // re-initialize every 500 update statements
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})
// Clean up remaining queue
if (counter % 500 !== 0) { bulk.execute(); }

The next example applies to the new MongoDB version 3.2 which has since deprecated the Bulk() API and provided a newer set of apis using bulkWrite().

MongoDB version 3.2 and greater:

var ops = [];
updatedJsonArray.forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "row_num": doc.row_num },
            "update": {
                "$set": { "value": doc.value }
            }
        }
    });

    if (ops.length === 500) {
        db.collection.bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db.collection.bulkWrite(ops);

Upvotes: 1

Related Questions