Updating data in MongoDB

Lecture



In the first chapter, we covered three of the four CRUD operations (create, read, update and delete). This chapter is devoted to the fourth: update. update has some quirks of its own, which is why we're dedicating a whole chapter to it.

Updating data in MongoDB

Updating data: replacement and $set

In its simplest form, update takes 2 arguments: a selector (where) to find the document, and what to update the matching field with. To make Moons gain some weight, we use the following query:

db.unicorns.update({name: 'Moons'}, {weight: 890}) 

(If, during your experiments, you deleted the data from the previously created unicorns collection, run remove on all the documents and re-insert them using the code from chapter 1)

In real life, of course, you should update documents by selecting them via _id, but since I don't know what _id MongoDB generated for you, we'll select by name instead - name. Now, let's take a look at the updated record:

db.unicorns.find({name: 'Moons'})

Here's the first surprise that update has in store for us. The document isn't found, because the second parameter is used to completely replace the original. In other words, update found the document by name and replaced it entirely with the new document (its second parameter). This is where it differs from the SQL UPDATE command. Sometimes this is exactly what you want, and it can be used for some genuinely dynamic updates. However, if you only need to change a couple of fields, it's best to use the $set modifier:

db.unicorns.update({weight: 590}, {$set: {name: 'Moons', dob: new Date(1999, 7, 18, 18, 44), loves: ['apple'], gender: 'm', vampires: 99}})
This will restore the previously lost fields. The weight field won't be overwritten, since we didn't pass it in the query. Now, if we run:
db.unicorns.find({name: 'Moons'}) 

we'll get the expected result. So, in the first example, the correct way to update weight would have been:

db.unicorns.update({name: 'Moons'}, {$set: {weight: 590}})
Update modifiers

Besides $set, there are other modifiers you can use for various neat tricks. All of these update modifiers operate on fields - so your document never ends up being overwritten entirely. For example, the $inc modifier is used to change a field by a positive (increase) or negative (decrease) amount. For instance, if the unicorn Pilot was mistakenly credited with killing a couple of extra vampires, we can fix that mistake as follows:

db.unicorns.update({name: 'Pilot'}, {$inc: {vampires: -2}}) 
If Aurora suddenly developed a sweet tooth, we can add the corresponding value to her loves field using the $push modifier:
db.unicorns.update({name: 'Aurora'}, {$push: {loves: 'sugar'}}) 
You can find information about the other modifiers in the Update section on the MongoDB website.
Update/insert

One of the pleasant surprises of the update operation is the ability to do an update/insert (upsert, from update - to update, and insert - to insert). An upsert updates the document if it's found, or creates a new one if it isn't. Upserts are a useful thing in some situations; you'll know it when you hit one. To allow insertion on update, set the third parameter to true.

A real-life example - a page-view counter for a website. If we want to see the number of page views in real time, we need to check whether a record already exists, and - depending on the result - perform either an update or an insert. If you omit (or set to false) the third parameter, the following example won't work:
db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}}); 
db.hits.find(); 
However, if you allow insertion on update, the results will be different:
db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}}, true); 
db.hits.find(); 
Since no documents with the page field equal to unicorns exist yet, a new document will be created. If you run this a second time, the existing document will be updated, and the hits field will increase to 2.
db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}}, true); 
db.hits.find();

Multiple updates

The last surprise of the update method is that, by default, it only updates a single document. So far this has made sense given the examples we've looked at. However, if you run something like:

db.unicorns.update({}, {$set: {vaccinated: true }}); 
db.unicorns.find({vaccinated: true}); 

then you would naturally expect all the unicorns to become (vaccinated). For this to work, you need to set the fourth parameter to true:

db.unicorns.update({}, {$set: {vaccinated: true }}, false, true); 
db.unicorns.find({vaccinated: true});

In this chapter

This chapter has wrapped up our introduction to the basic CRUD operations on collections. We took a close look at update and saw three of its interesting modes of operation. First, unlike the SQL UPDATE command, MongoDB's update replaces the entire document. That's why the $set modifier is so useful. Second, update supports an intuitively simple update/insert (upsert), which is especially useful with the $inc modifier. And finally, third, by default, update only updates the first document it finds.

Remember, we've been looking at MongoDB from the perspective of its console. The drivers and libraries you use may behave differently and implement a different API. For example, the Ruby driver merges the two parameters into a single hash: {:upsert => false, :multi => false}.

See also

  • [[b8218]]
  • [[b9900]]
  • [[b9901]]
  • [[b9902]]
  • [[b9903]]
  • [[b9904]]
  • [[b9905]]
  • [[b9906]]
  • [[b9907]]

See also

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Databases -MongoDB"

Terms: Databases -MongoDB