简体   繁体   中英

How do I update multiple documents in MongoDB with non similar update criteria in one command?

Consider we have a salary upgrade to all employees, where the salary increase is not fixed to all people, and it depends on some fields in the same employee document, how can I update all the salaries to mongo documents (one per employee) with one command?

Update

Consider I have the employee id or name, and the salary upgrade, and want to update all the documents with one command

Sample documents

{ _id : "11111", salary : (metric_1/metric_2) , name : "Androw", metric_1 : 12345, metric_2 : 222,
... }

{ _id : "22222", salary : (metric_1/metric_2) , name : "John", metric_1 : 999, metric_2 : 223, ... }

where metric_1 and metric_2 are random factors related to user interactions, and salary is a function of them.

The below command work great, and can do the required operation as needed, considering you have a list of users' ids or names you want to update (may be all)

db.salaries.aggregate( [ {$match : { _id:{$in:[ObjectId("563e1d9d04aa90562201fd5f"),ObjectId("564657f88f71450300e1fe0b")]}  } } , {$project: { rating: {$divide:["$metric_1","$metric_2"]} } } , {$out:"new_salaries"} ] )

The downside of the above command is that you have to have a new collection to insert the new updated fields, and if name the existing collection (salaries in this case), it will delete all the existing fields and just add the newly computed documents, which is unsafe to do, since other operations might have occurred during the new salaries computation.

Better approach

A better thing to do is to combine the aggregation pipelining with mongo's bulk operations to do batch update to our exiting collection. This way:

var salaries_to_update = db.salaries.aggregate( [ {$match : { _id:{$in:[ObjectId("563e1d9d04aa90562201fd5f"),ObjectId("564657f88f71450300e1fe0b")]}  } } , {$project: { rating: {$divide:["$metric_1","$metric_2"]} } } ] )

Then we do bulk update operation, which does batch of updates at once without a lot of processing and traffic headache back and forth.

var bulk = db.salaries.initializeUnorderedBulkOp()

salaries_to_update.forEach(salary){
    bulk.find( _id: salary._id).updateOne({$set:{salary:salary.salary}})
}

bulk.execute()

Ordered bulk operations are executed in an order (thus the name), halting when there's an error.

Unordered bulk operations are executed in no particular order (potentially in parallel) and these operations do not stop when an error occurs.

Thus, we use unordered bulk update here.

That's all

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM