Introduction to MongoDb with .NET part 10: updates

Introduction

In the previous post we looked at a couple of functions that can be applied in conjunction with searching and filtering. The limit function will return the first x number of items from the result set. The skip function skips the number of items specified by an integer argument. Limiting and skipping together are often used to page through a large result set. Finally we looked at the sort function which helps us sort the result set by one or more keys in ascending or descending order.

In this post we’ll start looking into updates.

The update function

The MongoDb JavaScript language offers an update method on collections and it seems to be the logical place to start. However, we’ll see that it can be cumbersome and dangerous to use in its basic form. This basic form of the update function takes two JSON documents: the first is a key to look for items to be updated and the second argument is a replacement document. The key term here is replacement. It replaces a current document with a new one entirely, regardless of what’s in the document to be updated. Hence, the function should really be called “replace”.

I actually don’t want to apply this function on our demo collections due to its clumsiness. We’ll instead create a small but disposable collection. Start mongo and mongod.exe. Enter the following commands in the mongo shell:

use model
db.people.insert({"name" : "john", "sport" : "football", "language" : "english"})
db.people.insert({"name" : "peter", "sport" : "basketball", "language" : "english"})
db.people.insert({"name" : "john", "sport" : "baseball", "language" : "english"})
db.people.insert({"name" : "mary", "sport" : "football", "language" : "german"})
db.people.insert({"name" : "susan", "sport" : "squash", "language" : "french"})
db.people.insert({"name" : "abdul", "sport" : "tennis", "language" : "arabic"})
db.people.insert({"name" : "kelly", "sport" : "tennis", "language" : "english"})

We now have a people collection with 7 documents. Let’s try to update Peter. He doesn’t like basketball anymore, he’s switched to golf. We’ll try to update this document with the update method:

db.people.update({"name" : "peter"}, {"sport" : "golf"})

The first argument is the search term. We can apply the same search techniques as for the find method. Then comes the replacement document. If you don’t know how to use the update method then you might just assume that the “sport” property will be updated to “golf”. However, if you run…

db.people.find()

…after the update statement you’ll find that the original document with peter has been replaced completely:

{ "_id" : ObjectId("57055d43b98ee40de403824e"), "sport" : "golf" }

Well, not completely as the _id field is that same as before. However, the rest of the properties are gone.

So if you want to update a single property with the update function then you’ll need to know the other properties in the document and include them in the replacement JSON document. You’ll probably see why this is not a very convenient approach especially for complex documents.

Update in its basic form is therefore not very usable in the Mongo shell. In my experience it is more applicable from the .NET driver where we select objects, modify their properties and send them as replacement objects to the database. The existing properties don’t need to be replaced, they are available from the search operation. We’ll see updates done with C# later on.

Let’s get rid of this “corrupted” record before we continue:

db.people.remove({"sport" : "golf"})

Updating specific fields

Fortunately the update method accepts operators similar to the ones we saw before, like $gt and $not. The $set operator sets the value of a specific property to the one supplied. Also, if the located document has no such property then it will be created. The $inc operator will increment a numeric field by the supplied value. It also creates the property if there’s none by the provided name.

We’ll give Susan a new favourite sport, racketball:

db.people.update({"name" : "susan"}, {$set : {"sport" : "racketball"}})

Here’s the updated Susan document:

{ "_id" : ObjectId("57055daeb98ee40de4038251"), "name" : "susan", "sport" : "racketball", "language" : "french" }

Let’s try to set a non-existing property for Susan:

db.people.update({"name" : "susan"}, {$set : {"points" : 10}})

Here it is:

{ "_id" : ObjectId("57055daeb98ee40de4038251"), "name" : "susan", "sport" : "racketball", "language" : "french", "points" : 10 }

Can we increment it with $inc? Absolutely, here’s how to add 2 points to Susan:

db.people.update({"name" : "susan"}, {$inc : {"points" : 2}})
{ "_id" : ObjectId("57055daeb98ee40de4038251"), "name" : "susan", "sport" : "racketball", "language" : "french", "points" : 12 }

Can we increment a non-existent property? Sure, it will be created for us with the increment set as the initial value:

db.people.update({"name" : "abdul"}, {$inc : {"points" : 8}})
{ "_id" : ObjectId("57055dcab98ee40de4038252"), "name" : "abdul", "sport" : "tennis", "language" : "arabic", "points" : 8 }

Notice that we have 2 people by the name “john”. Let’s see if update updates them all:

db.people.update({"name" : "john"}, {$set : {"points" : 20}})

The answer is no, it will only update the first matching document:

{ "_id" : ObjectId("57055d25b98ee40de403824d"), "name" : "john", "sport" : "football", "language" : "english", "points" : 20 }
{ "_id" : ObjectId("57055d6cb98ee40de403824f"), "name" : "john", "sport" : "baseball", "language" : "english" }

If we want to update all matching documents then we need to provide a third argument to the update function called “multi” and set it to true. Its default value is false:

db.people.update({"name" : "john"}, {$set : {"points" : 22}}, {multi : true})

Here’s the result:

{ "_id" : ObjectId("57055d25b98ee40de403824d"), "name" : "john", "sport" : "football", "language" : "english", "points" : 22 }
{ "_id" : ObjectId("57055d6cb98ee40de403824f"), "name" : "john", "sport" : "baseball", "language" : "english", "points" : 22 }

Here’s another example where we increment the points of every person by 5 where the current number of points is at least 10:

db.people.update({"points" : {$gt : 10}}, {$inc : {"points" : 5}},{multi : true})

Only Abdul has less then 8 points to begin with. The two Johns and Susan will get 5 extra points, the others are ignored since they have no points property currently.

What if I want to update every single document in the collection? We can supply an empty search parameter. This is analogous to a missing WHERE clause in an SQL UPDATE statement:

db.people.update({}, {$inc : {"points" : 5}},{multi : true})

All 6 persons will get 5 extra points. Therefore all of them now have a “points” property.

You can view all posts related to data storage on this blog here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: