27

How do I concatenate values from two string fields and put it into a third one?

I've tried this:

db.collection.update(
  { "_id": { $exists: true } },
  { $set: { column_2: { $add: ['$column_4', '$column_3'] } } },
  false, true
)

which doesn't seem to work though, and throws not ok for storage.

I've also tried this:

db.collection.update(
  { "_id": { $exists : true } },
  { $set: { column_2: { $add: ['a', 'b'] } } },
  false, true
)

but even this shows the same error not ok for storage.

I want to concatenate only on the mongo server and not in my application.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
Yogesh Mangaj
  • 3,200
  • 6
  • 32
  • 45
  • 1
    forEach is inefficient, multiple update is what I'm looking for. Also it doesn't explain, how to update the value of another field with the concatenated string, this is what I'm looking for `col3 = col1 + col2` "+" implying concatenation – Yogesh Mangaj Oct 10 '12 at 14:06
  • 2
    Mongodb does not, atm, allow the relfection of it's own document fields within the query without using JS functions. I would strongly advise not using the JS functions since they have been proven to make a query 10x slower and also have other problems. You will need to find some creative way of solving this – Sammaye Oct 10 '12 at 14:22
  • 1
    As to normal string concatenation you dont need a $add op since it is isn't like SQL, instead you can just do `column_2:'a'+'b'` – Sammaye Oct 10 '12 at 14:24

8 Answers8

32

You can use aggregation operators $project and $concat:

db.collection.aggregate([
  { $project: { newfield: { $concat: [ "$field1", " - ", "$field2" ] } } }
])
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
rebe100x
  • 1,473
  • 15
  • 18
  • 4
    The correct answer would include $out as the last pipeline stage, to output in the same collection (or a new one), since OP wants to update the collection – Jamby Sep 08 '16 at 18:33
  • 1
    MongoDB 4.2 now has a $merge pipeline stage which has some advantages over $out, depending on your performance, concurrency and consistency requirements. – Kenigmatic Oct 05 '19 at 00:06
  • What would the above aggregation look like with a step that updates the existing document with the new concatenated field? – OJT May 13 '21 at 15:46
10

Unfortunately, MongoDB currently does not allow you to reference the existing value of any field when performing an update(). There is an existing Jira ticket to add this functionality: see SERVER-1765 for details.

At present, you must do an initial query in order to determine the existing values, and do the string manipulation in the client. I wish I had a better answer for you.

William Z
  • 10,989
  • 4
  • 31
  • 25
  • 2
    FYI (7 years later) MongoDB has multiple ways to accomplish this without client-side code. This _was_ the best answer in 2012, but William Z's wish for a better answer has been granted. :) – Kenigmatic Oct 10 '19 at 21:55
5

You could use $set like this in 4.2 which supports aggregation pipeline in update.

db.collection.update(
   {"_id" :{"$exists":true}},
   [{"$set":{"column_2":{"$concat":["$column_4","$column_3"]}}}]
)
s7vr
  • 73,656
  • 11
  • 106
  • 127
2

Building on the answer from @rebe100x, as suggested by @Jamby ...

You can use $project, $concat and $out (or $merge) in an aggregation pipeline. https://docs.mongodb.org/v3.0/reference/operator/aggregation/project/ https://docs.mongodb.org/manual/reference/operator/aggregation/concat/ https://docs.mongodb.com/manual/reference/operator/aggregation/out/

For example:

    db.collection.aggregate(
       [
          { $project: { newfield: { $concat: [ "$field1", " - ", "$field2" ] } } },
          { $out: "collection" }
       ]
    )

With MongoDB 4.2 . . .

MongoDB 4.2 adds the $merge pipeline stage which offers selective replacement of documents within the collection, while $out would replace the entire collection. You also have the option of merging instead of replacing the target document.

    db.collection.aggregate(
       [
          { $project: { newfield: { $concat: [ "$field1", " - ", "$field2" ] } } },
          { $merge: { into: "collection", on: "_id", whenMatched: "merge", whenNotMatched: "discard" }
       ]
    )

You should consider the trade-offs between performance, concurrency and consistency, when choosing between $merge and $out, since $out will atomically perform the collection replacement via a temporary collection and renaming.

https://docs.mongodb.com/manual/reference/operator/aggregation/merge/ https://docs.mongodb.com/manual/reference/operator/aggregation/merge/#merge-out-comparison

Kenigmatic
  • 448
  • 6
  • 16
2

**

in my case this $concat worked for me ...

**

db.collection.update( { "_id" : {"$exists":true} }, 
   [ { 
       "$set" : { 
                 "column_2" :  { "$concat" : ["$column_4","$column_3"] }
                }
      }
   ]
Hanoj B
  • 350
  • 2
  • 12
1

You can also follow the below.

db.collectionName.find({}).forEach(function(row) { 
    row.newField = row.field1 + "-" + row.field2
    db.collectionName.save(row);
});
Kenigmatic
  • 448
  • 6
  • 16
ayyappa maddi
  • 854
  • 3
  • 10
  • 18
1

let suppose that you have a collection name is "myData" where you have data like this

{
"_id":"xvradt5gtg",
"first_name":"nizam",
"last_name":"khan",
"address":"H-148, Near Hero Show Room, Shahjahanpur",
}

and you want concatenate fields (first_name+ last_name +address) and save it into "address" field like this

{
"_id":"xvradt5gtg",
"first_name":"nizam",
"last_name":"khan",
"address":"nizam khan,H-148, Near Hero Show Room, Shahjahanpur",
}

now write query will be

{
var x=db.myData.find({_id:"xvradt5gtg"});
x.forEach(function(d)
    { 
        var first_name=d.first_name;
        var last_name=d.last_name;
        var _add=d.address;  
        var fullAddress=first_name+","+last_name+","+_add; 
        //you can print also
        print(fullAddress); 
        //update 
        db.myData.update({_id:d._id},{$set:{address:fullAddress}});
    })
}
Adam Bardon
  • 3,829
  • 7
  • 38
  • 73
Nizam Khan
  • 207
  • 2
  • 3
0

Find and Update Each Using For Loop

  1. Try This:

    db.getCollection('users').find({ }).forEach( function(user) {
        user.full_name = user.first_name + " " + user.last_name;
        db.getCollection('users').save(user);
    });
    
  2. Or Try This:

    db.getCollection('users').find({ }).forEach( function(user) {
        db.getCollection('users').update(
            { _id: user._id },
            { $set: { "full_name": user.first_name + " " + user.last_name } }
        )
    });
    
Sahil Thummar
  • 1,926
  • 16
  • 16