This page last changed on Jan 26, 2012 by dwight.

MongoDB supports atomic, in-place updates as well as more traditional updates for replacing an entire document.

update()

update() replaces the document matching criteria entirely with objNew. If you only want to modify some fields, you should use the $ modifiers below.

Here's the MongoDB shell syntax for update():

db.collection.update( criteria, objNew, upsert, multi )

Arguments:

  • criteria - query which selects the record to update;
  • objNew - updated object or $ operators (e.g., $inc) which manipulate the object
  • upsert - if this should be an "upsert" operation; that is, if the record(s) do not exist, insert one. Upsert only inserts a single document.
  • multi - indicates if all documents matching criteria should be updated rather than just one. Can be useful with the $ operators below.
If you are coming from SQL, be aware that by default, update() only modifies the first matched object. If you want to modify all matched objects, you need to use the multi flag.
It is important to understand that upsert can only insert a single document. Upsert means "update if present; insert (a single document) if missing".

save() in the mongo shell

The save() helper method in the mongo shell provides a shorthand syntax to perform an update of a single document with upsert semantics:

> // x is some JSON style object
> db.mycollection.save(x); // updates if exists; inserts if new
> 
> // equivalent to:
> db.mycollection.update( { _id: x._id }, x, /*upsert*/ true );

Modifier Operations

Modifier operations are highly-efficient and useful when updating existing values; for instance, they're great for incrementing a number.

So, while a conventional implementation does work:

var j=myColl.findOne( { name: "Joe" } );
j.n++;
myColl.save(j);

a modifier update has the advantages of avoiding the latency involved in querying and returning the object. The modifier update also features operation atomicity and very little network data transfer.

To perform an atomic update, simply specify any of the special update operators (which always start with a '$' character) with a relevant update document:

db.people.update( { name:"Joe" }, { $inc: { n : 1 } } );

The preceding example says, "Find the first document where 'name' is 'Joe' and then increment 'n' by one."

While not shown in the examples, most modifier operators will accept multiple field/value pairs when one wishes to modify multiple fields. For example, the following operation would set x to 1 and y to 2:

{ $set : { x : 1 , y : 2 } }

Also, multiple operators are valid too:

{ $set : { x : 1 }, $inc : { y : 1 } }

$inc

{ $inc : { field : value } }

increments field by the number value if field is present in the object, otherwise sets field to the number value. This can also be used to decrement by using a negative value.

$set

{ $set : { field : value } }

sets field to value. All datatypes are supported with $set.

$unset

{ $unset : { field : 1} }

Deletes a given field. v1.3+

$push

{ $push : { field : value } }

appends value to field, if field is an existing array, otherwise sets field to the array [value] if field is not present. If field is present but is not an array, an error condition is raised.

Multiple arrays may be updated in one operation by comma separating the field : value pairs:

{ $push : { field : value, field2 : value2 } }

$pushAll

{ $pushAll : { field : value_array } }

appends each value in value_array to field, if field is an existing array, otherwise sets field to the array value_array if field is not present. If field is present but is not an array, an error condition is raised.

$addToSet and $each

{ $addToSet : { field : value } }

Adds value to the array only if its not in the array already, if field is an existing array, otherwise sets field to the array value if field is not present. If field is present but is not an array, an error condition is raised.

To add a list of several values to the set use the $each qualifier:

{ $addToSet : { a : { $each : [ 3 , 5 , 6 ] } } }

$pop

{ $pop : { field : 1  } }

removes the last element in an array (ADDED in 1.1)

{ $pop : { field : -1  } }

removes the first element in an array (ADDED in 1.1) |

$pull

{ $pull : { field : _value } }

removes all occurrences of value from field, if field is an array. If field is present but is not an array, an error condition is raised.

In addition to matching an exact value you can also use expressions ($pull is special in this way):

{ $pull : { field : {field2: value} } } removes array elements with field2 matching value 
{ $pull : { field : {$gt: 3} } } removes array elements greater than 3
{ $pull : { field : {<match-criteria>} } } removes array elements meeting match criteria
Because of this feature, to use the embedded doc as a match criteria, you cannot do exact matches on array elements.

$pullAll

{ $pullAll : { field : value_array } }

removes all occurrences of each value in value_array from field, if field is an array. If field is present but is not an array, an error condition is raised.

$rename

Version 1.7.2+ only.

{ $rename : { old_field_name : new_field_name } }

Renames the field with name 'old_field_name' to 'new_field_name'. Does not expand arrays to find a match for 'old_field_name'.

$bit

v1.8+.

{$bit : { field : {and : 5}}}
{$bit : {field : {or : 43}}}
{$bit : {field : {and : 5, or : 2}}}

Does a bitwise update of field. Can only be used with integers.

The $ positional operator

v1.4+

The $ operator (by itself) means "position of the matched array item in the query". Use this to find an array member and then manipulate it. For example:

> t.find()
{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
  "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )

> t.find()
{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
  "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

Currently the $ operator only applies to the first matched item in the query. For example:

> t.find();
{ "_id" : ObjectId("4b9e4a1fc583fa1c76198319"), "x" : [ 1, 2, 3, 2 ] }
> t.update({x: 2}, {$inc: {"x.$": 1}}, false, true);
> t.find();
{ "_id" : ObjectId("4b9e4a1fc583fa1c76198319"), "x" : [ 1, 3, 3, 2 ] }

The positional operator cannot be combined with an upsert since it requires a matching array element. If your update results in an insert then the "$" will literally be used as the field name.

Using "$unset" with an expression "array.$" will result in the array item becoming null, not being removed. You can issue an update with "{$pull:{x:null}}" to remove all nulls. $pull can now do much of this so this example is now mostly historical.
> t.insert({x: [1,2,3,4,3,2,3,4]})
> t.find()
{ "_id" : ObjectId("4bde2ad3755d00000000710e"), "x" : [ 1, 2, 3, 4, 3, 2, 3, 4 ] }
> t.update({x:3}, {$unset:{"x.$":1}})
> t.find()
{ "_id" : ObjectId("4bde2ad3755d00000000710e"), "x" : [ 1, 2, null, 4, 3, 2, 3, 4 ] }

Upserts with Modifiers

You may use upsert with a modifier operation. In such a case, the modifiers will be applied to the update criteria member and the resulting object will be inserted. The following upsert example may insert the object {name:"Joe",x:1,y:1}.

db.people.update( { name:"Joe" }, { $inc: { x:1, y:1 } }, true );

There are some restrictions. A modifier may not reference the _id field, and two modifiers within an update may not reference the same field, for example the following is not allowed:

db.people.update( { name:"Joe" }, { $inc: { x: 1 }, $set: { x: 5 } } );

Pushing a Unique Value

To add a value to an array only if not already present:

Starting in 1.3.3, you can do

update( {_id:'joe'},{"$addToSet": { tags : "baseball" } } );

For older versions, add $ne : <value> to your query expression:

update( {_id:'joe', tags: {"$ne": "baseball"}},
        {"$push": { tags : "baseball" } } );

Checking the Outcome of an Update Request

As described above, a non-upsert update may or may not modify an existing object. An upsert will either modify an existing object or insert a new object. The client may determine if its most recent message on a connection updated an existing object by subsequently issuing a getlasterror command ( db.runCommand( "getlasterror" ) ). If the result of the getlasterror command contains an updatedExisting field, the last message on the connection was an update request. If the updatedExisting field's value is true, that update request caused an existing object to be updated; if updatedExisting is false, no existing object was updated. An "upserted" field will contain the new _id value if an insert is performed (new as of 1.5.4).

Notes

Object Padding

When you update an object in MongoDB, the update occurs in-place if the object has not grown in size. This is good for insert performance if the collection has many indexes.

Mongo adaptively learns if objects in a collection tend to grow, and if they do, it adds some padding to prevent excessive movements.  This statistic is tracked separately for each collection. More info here.

Blocking

Starting in 1.5.2, multi updates yield occasionally so you can safely update large amounts of data. If you want a multi update to be truly isolated (so no other writes happen while processing the affected documents), you can use the $atomic flag in the query expression. For example:

db.students.update({score: {$gt: 60}, $atomic: true}, {$set: {pass: true}}, false, true)
sharding
$atomic is not supported with Sharding. If used it results in no updates and the getLastError Command returns error information.
atomic
$atomic only means that the update will not yield for other operations while running. It does not mean that the operation is "all or nothing". See here.

Field (re)order

During an update the field order may be changed. There is no guarantee that the field order will be consistent, or the same, after an update. At the moment, if the update can be applied in place then the order will be the same (with additions applied at the end), but if a move is required for the document (if the currently allocated space is not sufficient for the update) then the fields will be reordered (alphanumerically).

See Also

test showing usage of push, pushAll, pull, and pullAll using mongo-ruby-driver

http://gist.github.com/169258

  • Jon Hancock
Posted by at Aug 17, 2009 13:32

How do I remove a single item? For instance if I have the object

{foo: {bar: {baz: 'hello}}}

and I wanted to remove bar (including it's embedded document). It would be nice to have a way to do this in an update statement.

Posted by at Nov 12, 2009 01:45

You can't, yet, but $unset is coming in 1.1.4 (see http://jira.mongodb.org/browse/SERVER-134)

Posted by kristina at Nov 12, 2009 11:48

Is there a way to support uniquness (or order) on list elements.
I.e. when using $push, you can add duplicate elements like:

> db.c.findOne()
{"_id" :  ObjectId( "4b040ab17b5a103277c14568")  , "arr" : [] , "name" : "a"}
> db.c.update({name:'a'}, {$push: {arr: 1}})
> db.c.findOne()
{"_id" :  ObjectId( "4b040ab17b5a103277c14568")  , "name" : "a" , "arr" : [1]}
> db.c.update({name:'a'}, {$push: {arr: 1}})
> db.c.findOne()
{"_id" :  ObjectId( "4b040ab17b5a103277c14568")  , "name" : "a" , "arr" : [1,1]}

... but what if I need to maintain a set of unique elements?

For example, let's say I want to keep a list of all books owned by a person:

{"_id": ObjectId("..."), "name": "John", "books": set(["The Adventures of Tom Sawyer", "Javascript Bible"])}

I'd like a way to add a book to the set and check for existence. Is this possible with MongoDB?

Posted by at Nov 18, 2009 10:10

See http://jira.mongodb.org/browse/SERVER-176.

Posted by kristina at Nov 20, 2009 10:52

Is it possible to use $pull to remove an object in an array? For example if there was an object like:

{_id:1, props: [ {name:"n1",val:"v1"}, {name:"n2", val:"v2} ]}

is there a way to pull from the props array?

Posted by at Nov 27, 2009 00:28

It took my some time before I understood that update only updates the first record it finds.

I tried stuff like:

db.mynames.update({_id:{$gte:0}},{$inc:{age:}});

I just assumed that it would update all records.

Posted by at Dec 05, 2009 16:19

I mean

db.mynames.update({_id : {$gte:0}},{$inc:{age:1}});

Posted by at Dec 05, 2009 16:22

see "$push a Unique Value" above.

Gregg Lind, happy mongo user

Posted by at Dec 05, 2009 16:28

multi update is now an option

Posted by dwight at Dec 14, 2009 14:26

Let's say I have the following object:

{_id:1, elements: [ {name:n1,val:v1}, {name:n2,val:v2} ]}

I want to remove items under "elements" whose name matches a specified value. Can this be done with $pull?

For example, I want to remove items whose name = n1 such that after removing, the object above become:

{_id:1, elements: [ {name:n2,val:v2} ]}

Is this possible?

Posted by at Dec 21, 2009 22:51

in 1.3.x it is:
db.foo.update

( {} , { $pull : [ { name : n1 } ] } , false , true )
Posted by eliot at Dec 22, 2009 06:52

Let's say I have this:

{_id:1, foo: { anotherfoo: 100 } }

I want to increment the field anotherfoo using $inc

I'm doing this in Java but this code does not work

coll.update(new BasicDBObject("_id", new ObjectId(id)), new BasicDBObject("$inc", new BasicDBObject("foo",new BasicDBObject("anotherfoo", 100)));

is there a way to do this?

thanks!

Posted by at Dec 31, 2009 05:50

sorry: i reply in the correct way

Let's say I have this:

{_id:1, foo: {anotherfoo: 100} }

I want to increment the field anotherfoo using $inc

I'm doing this in Java but this code does not work

coll.update(new BasicDBObject("_id", new ObjectId(id)), new BasicDBObject("$inc", new BasicDBObject("foo",new BasicDBObject("anotherfoo", 100)));

is there a way to do this?

thanks!

Posted by at Dec 31, 2009 05:54

answering to myself, ftw

coll.update(new BasicDBObject("_id", id)), new BasicDBObject("$inc", new BasicDBObject("foo.anotherfoo", 100)));
Posted by at Dec 31, 2009 06:25

Try this: (I use 1.3 dont know if 1.2 works)

db.x.y.update( {_id:1}, { $pull:{elements:{name:n1} } } )
Posted by at Jan 05, 2010 07:54

I'm trying to update a subObject;

{ _id:1, comments:[{_id:A1,foo:bar},{_id:A2,foo:duh}] }

I want to update {_id:A2,foo:duh} to {_id:A2,foo:blah}.

collection.update(new BasicDBObject("comments._id", A2)),new BasicDBObject("$set", new BasicDBObject("foo", "blah")));

does not throw an error, but does not update either.

Posted by at Jan 18, 2010 10:30
Canonical URL
Document generated on Apr 10, 2012