Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update MongoDB field using value of another field

In MongoDB, is it possible to update the value of a field using the value from another field? The equivalent SQL would be something like:

UPDATE Person SET Name = FirstName + ' ' + LastName 

And the MongoDB pseudo-code would be:

db.person.update( {}, { $set : { name : firstName + ' ' + lastName } ); 
like image 689
Chris Fulstow Avatar asked Oct 20 '10 05:10

Chris Fulstow


People also ask

Is it possible to update MongoDB field using value of another field?

Starting from MongoDB 4.2 you can perform Updates with an Aggregation Pipeline. An aggregation pipeline enables more expressive updates including calculated fields and references to other field values in the same document.

How do I update two values in MongoDB?

Update Multiple Fields of a Single Document. We can use $set and $inc operators to update any field in MongoDB. The $set operator will set the newly specified value while the $inc operator will increase the value by a specified value.

How do I Upsert data in MongoDB?

Upsert is a combination of insert and update (inSERT + UPdate = upsert). We can use the upsert with different update methods, i.e., update, findAndModify, and replaceOne. Here in MongoDB, the upsert option is a Boolean value. Suppose the value is true and the documents match the specified query filter.


1 Answers

The best way to do this is in version 4.2+ which allows using of aggregation pipeline in the update document and the updateOne, updateMany or update collection methods. Note that the latter has been deprecated in most if not all languages drivers.

MongoDB 4.2+

Version 4.2 also introduced the $set pipeline stage operator which is an alias for $addFields. I will use $set here as it maps with what we are trying to achieve.

db.collection.<update method>(     {},     [         {"$set": {"name": { "$concat": ["$firstName", " ", "$lastName"]}}}     ] ) 

Note that square brackets in the second argument to the method which defines an aggregation pipeline instead of a plain update document. Using a plain document will not work correctly.

MongoDB 3.4+

In 3.4+ you can use $addFields and the $out aggregation pipeline operators.

db.collection.aggregate(     [         { "$addFields": {              "name": { "$concat": [ "$firstName", " ", "$lastName" ] }          }},         { "$out": "collection" }     ] ) 

Note that this does not update your collection but instead replaces the existing collection or creates a new one. Also for update operations that require "typecasting" you will need client-side processing, and depending on the operation, you may need to use the find() method instead of the .aggreate() method.

MongoDB 3.2 and 3.0

The way we do this is by $projecting our documents and using the $concat string aggregation operator to return the concatenated string. From there, you then iterate the cursor and use the $set update operator to add the new field to your documents using bulk operations for maximum efficiency.

Aggregation query:

var cursor = db.collection.aggregate([      { "$project":  {          "name": { "$concat": [ "$firstName", " ", "$lastName" ] }      }} ]) 

MongoDB 3.2 or newer

from this, you need to use the bulkWrite method.

var requests = []; cursor.forEach(document => {      requests.push( {          'updateOne': {             'filter': { '_id': document._id },             'update': { '$set': { 'name': document.name } }         }     });     if (requests.length === 500) {         //Execute per 500 operations and re-init         db.collection.bulkWrite(requests);         requests = [];     } });  if(requests.length > 0) {      db.collection.bulkWrite(requests); } 

MongoDB 2.6 and 3.0

From this version, you need to use the now deprecated Bulk API and its associated methods.

var bulk = db.collection.initializeUnorderedBulkOp(); var count = 0;  cursor.snapshot().forEach(function(document) {      bulk.find({ '_id': document._id }).updateOne( {         '$set': { 'name': document.name }     });     count++;     if(count%500 === 0) {         // Excecute per 500 operations and re-init         bulk.execute();         bulk = db.collection.initializeUnorderedBulkOp();     } })  // clean up queues if(count > 0) {     bulk.execute(); } 

MongoDB 2.4

cursor["result"].forEach(function(document) {     db.collection.update(         { "_id": document._id },          { "$set": { "name": document.name } }     ); }) 
like image 130
styvane Avatar answered Sep 19 '22 15:09

styvane