Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append a string to the end of an existing field in MongoDB

Tags:

mongodb

I have a document with a field containing a very long string. I need to concatenate another string to the end of the string already contained in the field.

The way I do it now is that, from Java, I fetch the document, extract the string in the field, append the string to the end and finally update the document with the new string.

The problem: The string contained in the field is very long, which means that it takes time and resources to retrieve and work with this string in Java. Furthermore, this is an operation that is done several times per second.

My question: Is there a way to concatenate a string to an existing field, without having to fetch (db.<doc>.find()) the contents of the field first? In reality all I want is (field.contents += new_string).

I already made this work using Javascript and eval, but as I found out, MongoDB locks the database when it executes javascript, which makes the overall application even slower.

like image 745
pico Avatar asked May 26 '14 11:05

pico


3 Answers

Starting Mongo 4.2, db.collection.updateMany() can accept an aggregation pipeline, finally allowing the update of a field based on its current value:

// { a: "Hello" }
db.collection.updateMany(
  {},
  [{ $set: { a: { $concat: [ "$a", "World" ] } } }]
)
// { a: "HelloWorld" }
  • The first part {} is the match query, filtering which documents to update (in this case all documents).

  • The second part [{ $set: { a: { $concat: [ "$a", "World" ] } } }] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline). $set (alias of $addFields) is a new aggregation operator which in this case replaces the field's value (by concatenating a itself with the suffix "World"). Note how a is modified directly based on its own value ($a).

like image 130
Xavier Guihot Avatar answered Nov 17 '22 06:11

Xavier Guihot


For example (it's append to the start, the same story ):

before

{ "_id" : ObjectId("56993251e843bb7e0447829d"), "name" : "London City", "city" : "London" }

db.airports
   .find( { $text: { $search: "City" } })
   .forEach(
       function(e, i){ 
           e.name='Big ' + e.name; 
           db.airports.save(e);
       }
    )

after:

{ "_id" : ObjectId("56993251e843bb7e0447829d"), "name" : "Big London City", "city" : "London" }

like image 20
Iurii Perevertailo Avatar answered Nov 17 '22 07:11

Iurii Perevertailo


Old topic but i had the same problem. Since mongo 2.4, you can use $concat from aggregation framework.

Example

Consider these documents :

{
    "_id" : ObjectId("5941003d5e785b5c0b2ac78d"),
    "title" : "cov"
}

{
    "_id" : ObjectId("594109b45e785b5c0b2ac97d"),
    "title" : "fefe"
}

Append fefe to title field :

db.getCollection('test_append_string').aggregate(
    [
        { $project: { title: { $concat: [ "$title", "fefe"] } } }
    ]
)

The result of aggregation will be :

{
    "_id" : ObjectId("5941003d5e785b5c0b2ac78d"),
    "title" : "covfefe"
}

{
    "_id" : ObjectId("594109b45e785b5c0b2ac97d"),
    "title" : "fefefefe"
}

You can then save the results with a bulk, see this answer for that.

like image 6
Olivier Ziadé Avatar answered Nov 17 '22 07:11

Olivier Ziadé