Introduction to MongoDb with .NET part 11: various other update operations
April 15, 2016 Leave a comment
Introduction
In the previous post we started looking into how updates are performed in the MongoDb client. We saw the update function in action with a number of examples. The most basic usage of update is cumbersome in the client as it really only replaces the existing document(s) with a new one. Fortunately there are various $ operators that let us update a single property of a document. We also saw the role of the “multi” argument. If set to true then the update function will update every single document that matches the search criteria. Otherwise only the first matching document will be updated.
In this post we’ll look into various other operations related to updates.
Remove a property completely
The $unset operator is the opposite of $set which we saw in action in the previous post. I don’t want to remove any property from our demo databases “restaurants” and “zipcodes”. I’ll reuse the small people collection here which we built earlier. Every document has a property called “language”. Let’s remove it for Mary:
db.people.update({"name" : "mary"}, {$unset: {"language" : 1}});
Here’s Mary:
{ "_id" : ObjectId("57055d9bb98ee40de4038250"), "name" : "mary", "sport" : "football", "points" : 5 }
In fact we can remove the language property from every document with an empty search term:
db.people.update({}, {$unset: {"language" : 1}}, {multi : true});
The language property of all documents in the people collection has been removed.
Array-related updates
For these examples let’s add an array field to every document in the people collection first:
db.people.update({}, {$set : {"foods" : ["fish", "chips", "chololate"]}}, {multi: true});
We’ve just added a new array property to every document in the people collection and initialised it to the same 3 items.
Arrays and array elements can be updated in various ways in MongoDb. Let’s go through them one by one.
The $set operator can be used to update an individual element in an array by its index where the index is 0-based. E.g. Susan doesn’t like fish any more and we know that fish has the index 1 in every array. We’ll change it to lamb:
db.people.update({"name" : "susan"}, {$set : {"foods.1" : "lamb"}});
Note the dot-notation with an index after the name of the array property. Here’s Susan:
{ "_id" : ObjectId("57055daeb98ee40de4038251"), "name" : "susan", "sport" : "racketball", "points" : 22, "foods" : [ "fish", "lamb", "chololate" ] }
What happens if we provide an index that is out of bounds like here?
db.people.update({"name" : "susan"}, {$set : {"foods.6" : "lamb"}});
MongoDb resolves this by adding nulls to the missing positions:
{ "_id" : ObjectId("57055daeb98ee40de4038251"), "name" : "susan", "sport" : "racketball", "points" : 22, "foods" : [ "fish", "lamb", "chololate", null, null, null, "lamb" ] }
The $push operator lets us add a new item to the end of the array:
db.people.update({"name" : "abdul"}, {$push : {"foods" : "rice"}});
Here’s Abdul:
{ "_id" : ObjectId("57055dcab98ee40de4038252"), "name" : "abdul", "sport" : "tennis", "points" : 13, "foods" : [ "fish", "chips", "chololate", "rice" ] }
We can pop an item from the beginning or the tail of the array by the $pop operator and an integer argument. 1 will pop the rightmost and -1 the leftmost element:
db.people.update({"name" : "kelly"}, {$pop : {"foods" : -1}});
{ "_id" : ObjectId("57055e0fb98ee40de4038253"), "name" : "kelly", "sport" : "tennis", "points" : 5, "foods" : [ "chips", "chololate" ] }
We can add multiple elements at once with the $pushAll operator:
db.people.update({"name" : "kelly"}, {$pushAll : {"foods" : ["pasta", "pizza", "falafel"]}});
{ "_id" : ObjectId("57055e0fb98ee40de4038253"), "name" : "kelly", "sport" : "tennis", "points" : 5, "foods" : [ "chips", "chololate", "pasta", "pizza", "falafel" ] }
We can also remove elements by value with the $pull operator. We’ll remove fish from Kelly’s foods array:
db.people.update({"name" : "kelly"}, {$pull : {"foods" : "fish"}});
{ "_id" : ObjectId("57055e0fb98ee40de4038253"), "name" : "kelly", "sport" : "tennis", "points" : 5, "foods" : [ "chips", "chololate", "pasta", "pizza", "falafel" ] }
I’ve actually just noticed that I have a typo on chocolate. We can easily update it:
db.people.update({}, {$pull : {"foods" : "chololate"}}, {multi : true}) db.people.update({}, {$push : {"foods" : "chocolate"}}, {multi : true})
Let’s also remove all null values from the foods array:
db.people.update({}, {$pull : {"foods" : null}}, {multi : true})
We also have a $pullAll operator to remove multiple items at once. Only those items will be removed from the array that figure there of course:
db.people.update({"name" : "kelly"}, {$pullAll : {"foods" : ["pasta", "pizza", "tacos"]}})
Pasta and pizza will be removed from Kelly’s foods array, tacos will be ignored obviously.
The $addToSet operator is very useful if we want to hold only unique values in an array. E.g. the foods array should probably not hold duplicated items. So $addToSet will add the items to an array only if it doesn’t contain one yet:
db.people.update({"name" : "kelly"}, {$addToSet : {"foods" : ["pasta", "pizza", "falafel", "chips"]}})
Only pasta and pizza will be added to Kelly’s foods array as it already contains falafel and chips.
Upserts
To wrap up this post and updates in general we’ll look at upserts. An upsert is a combination of update and insert. It’s quite a common requirement that if an object is supplied to an update operation then if there’s already an item by those properties then it’s updated otherwise a new one is inserted. Upserts can be performed using the “upsert” operator much the same way as we attached the multi operator to the update query. Here’s an example where an existing item Abdul will have its sport property updated to cricket:
db.people.update({"name" : "abdul"}, {$set : {"sport" : "cricket"}}, {upsert : true})
On the other hand if we try to update the sport property of a nonexistent document, like here…:
db.people.update({"name" : "andrew"}, {$set : {"sport" : "swimming"}}, {upsert : true})
…then we’ll get a different response type from the server:
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("570ff0b4ce1104160e789021") })
The upserted count is 1. Here’s Andrew:
{ "_id" : ObjectId("570ff0b4ce1104160e789021"), "name" : "andrew", "sport" : "swimming" }
Those were the main features of updates in MongoDb. In the next post we’ll look at deletions.
You can view all posts related to data storage on this blog here.