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 } );
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.
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.
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.
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.
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.
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.
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.
var cursor = db.collection.aggregate([ { "$project": { "name": { "$concat": [ "$firstName", " ", "$lastName" ] } }} ]) 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); } 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(); } cursor["result"].forEach(function(document) { db.collection.update( { "_id": document._id }, { "$set": { "name": document.name } } ); })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With