I am Hack Sparrow
Captain of the Internets.

The MongoDB Tutorial

The best MongoDB Tutorial on the Web


Even as I write this, there are numerous MongoDB tutorials on the Web, including the official one at www.mongodb.org. They all have a big problem - they all suck. They are either a headache to follow, or miss the basics, or are extremely hard to absorb information from. I want to change that, I want to create the best ever MongoDB tutorial on the Web - a tutorial that efficiently focuses on orienting users to MongoDB.

While this tutorial is not going to be an in-depth article on MongoDB, it will most definitely ensure you a pleasant kickstart of your MongoDB journey.

You may be aware about try.mongodb.org, the online limited-access Mongo shell. Don't bother with it for two reasons: i. This tutorial covers whatever the built-in tutorial there has to offer (and much more), ii. The limitations and bugs in the custom shell might create misconceptions about MongoDB.

I am starting this tutorial assuming you already have MongoDB installed and running on your system. If you haven't installed it yet, get it installed first.

  1. How to install MongoDB on Mac OS X
  2. How to install MongoDB on Linux
  3. How to install MongoDB on Windows

Ok, now that you have MongoDB installed, let's proceed with the tutorial.

First, let's have the MongoDB server running:

$ mongod

Then let's connect to the server using the mongo client:

$ mongo

Note that all the commands in the tutorial will be typed at the mongo client's command prompt >.

Getting acquainted with MongoDB

MongoDB is a document-oriented database system (a kind of NoSQL) made up of the hierarchy of database > collection > document > field > key:value. Here is an approximate comparison between MongoDB and SQL data models.

MongoDB : SQL
---------------------
database : database
collection : table
document : row
field : -
{key:value} : -

The similarity (distant) ends at the SQL's row level. It is a good idea to remember the above comparison because I will switch entirely to Mongo-esque from SQL-esque - no more terms like table, row etc.

Next thing to note: the Mongo shell is a fully functional JavaScript shell. You can perform JavaScript operations on data before inserting to or retrieving from the database. The shell supports all standard JavaScript API along with some Mongo-specific custom APIs. I think this feature makes MongoDB an extremely powerful and fascinating database system.

Before you get your hands dirty with the data in the database, I think you should know how to deal with the database system first. Here are the basics of how you interact with MongoDB.

To see the list of databases in the system:

> show dbs
bands 0.203125GB
movies (empty)
scores (empty)

Just like in SQL, you need to first select a database to be able to perform operations on it. To select a database:

> use movies
switched to db movies

To find out the currently selected database:

> db.getName()
movies

To delete / drop a database, make sure you have selected the database and then do this:

> use scores
> db.dropDatabase()
{"dropped" : "scores", "ok" : 1 }

To see the collections in a databases:

> show collections

or

> db.getCollectionNames()

Unlike in SQL, databases in MongoDB are created lazily. You don't create databases using any explicit commands. Depending on your commands, the system creates it for you once it determines a database needs to be created. To begin creating a new database, first execute the use command to switch to a new database, and then issue a command which saves some data to the database - this results in the creation on the new database.

Let's create a new database named "movies":

> use movies
switched to db movies
> db.comedy.insert({name:"Bill & Ted's Excellent Adventure", year:1989})

That above commands resulted in the creation of the new database named "movies". In the process a new collection called "comedy" was also created in the database.

Now that you know how to handle the database, time to get your hands dirty with the data in the database!

Getting your hands dirty with data in MongoDB

What good is a MongoDB tutorial that does not show how CRUD (Create, Read, Update, Delete) works in MongoDB, preferably with examples? As this tutorial aims to be the best MongoDB tutorial in the world it will show you how CRUD works in MongoDB.

Note: all database commands are called on the MongoDB database object named db. db refers to the database you have selected using the use command.

Create / add data in MongoDB


To create documents in a collection:

> db.comedy.insert({name:"Wayne's World", year:1992})
> db.comedy.insert({name:'The School of Rock', year:2003})

The two commands above added two more documents to the collection named "comedy" in the "movies" database.

You could have done the same thing using the save command instead of the insert command.

> db.comedy.save({name:"Wayne's World", year:1992})
> db.comedy.save({name:'The School of Rock', year:2003})

The difference between insert and save is this:

insert will always add a new document.
save does an insert if there is no _id key in the object it receives, else it does an update.

I personally see save to be quite pointless. Unless you are too hooked to the spelling and sound of save, it is recommended to use insert to add new documents to a collection, and update to update collections.

Read data from MongoDB


To read data from a collection:

> db.comedy.find()
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure", "year" : 1989 }
{ "_id" : ObjectId("4e9ebb478c02b838880ef413"), "name" : "Wayne's World", "year" : 1992 }
{ "_id" : ObjectId("4e9ebd5d8c02b838880ef414"), "name" : "The School of Rock", "year" : 2003 }

That got the whole collection. To limit it to just two:

> db.comedy.find().limit(2)
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure", "year" : 1989 }
{ "_id" : ObjectId("4e9ebb478c02b838880ef413"), "name" : "Wayne's World", "year" : 1992 }

Similar to using find().limit(1), there is a function called findOne(), which will get you only one document in the result.

db.comedy.findOne()
{
"_id" : ObjectId("4e9ebb318c02b838880ef412"),
"name" : "Bill & Ted's Excellent Adventure",
"year" : 1989
}

What if you want to conditionally find documents?

> db.comedy.find({year:{$lt:1994}})
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure", "year" : 1989 }
{ "_id" : ObjectId("4e9ebb478c02b838880ef413"), "name" : "Wayne's World", "year" : 1992 }

In the above example we looked for documents with their year field with value less than 1994. The $lt you saw are one of the many conditional operators in MongoDB. Here are the rest.

$lt - ' $lte - ' $gte - '>='
$ne - '!='
$in - 'is in array'
$nin - '! in array'

And how do we do an 'equal to' (==) query? Just match the value for the queried key:

> db.comedy.find({year:1992})
{ "_id" : ObjectId("4e9ebb478c02b838880ef413"), "name" : "Wayne's World", "year" : 1992 }

We can even use regular expressions in our queries!

> db.comedy.find({name:{$regex: /bill|steve/i}})
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure" }

Now let's try a more complicated use of regex in a query.

> var names = ['bill', 'steve']
> names = names.join('|');
> var re = new RegExp(names, 'i')
> db.comedy.find({name:{$regex: re}})
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure" }

What if you want to get only some fields in the result?

> db.comedy.find({year:{'$lt':1994}}, {name:true})
{ "_id" : ObjectId("4e9ebb318c02b838880ef412"), "name" : "Bill & Ted's Excellent Adventure" }
{ "_id" : ObjectId("4e9ebb478c02b838880ef413"), "name" : "Wayne's World" }

In the above example, we excluded a field by not specifying it in the second parameter of the find() function. To get more than one exclusive fields in the results you might do something like db.comedy.find({year:{'$lt':1994}}, {name:true, director:true}). Note, the director field is still not set, so you won't see any director info.

The _id field is always returned by default. If you want to get rid of it, you need to explicitly do so using the option explained next.

What if you want to get all, except some fields in the result?

> db.comedy.find({year:{'$lt':1994}}, {name:false})
{ "_id" : ObjectId("4ed201525bfc796ab22f9ee1"), "year" : 1989 }
{ "_id" : ObjectId("4ed201605bfc796ab22f9ee2"), "year" : 1992 }

Unfortunately, as of this writing field inclusion and exclusion cannot be used together.

I want to show you some interesting Mongo-specific queries (using the dot notation), so let's create some documents in a collection named 'articles':

> db.articles.insert({title:'The Amazingness of MongoDB', meta:{author:'Mike Vallely', date:1321958582668, likes:23, tags:['mongo', 'amazing', 'mongodb']}, comments:[{by:'Steve', text:'Amazing article'}, {by:'Dave', text:'Thanks a ton!'}]})
> db.articles.insert({title:'Mongo Business', meta:{author:'Chad Muska', date:1321958576231, likes:10, tags:['mongodb', 'business', 'mongo']}, comments:[{by:'Taylor', text:'First!'}, {by:'Rob', text:'I like it'}]})
> db.articles.insert({title:'MongoDB in Mongolia', meta:{author:'Ghenghiz Khan', date:1321958598538, likes:75, tags:['mongo', 'mongolia', 'ghenghiz']}, comments:[{by:'Alex', text:'Dude, it rocks'}, {by:'Steve', text:'The best article ever!'}]})

To search an object inside an object, just use the regular JavaScript dot notation of the target object as the key AND quote it. For example, to query the meta.likes object, you might do something like this:

> db.articles.find({'meta.author':'Chad Muska'})
> db.articles.find({'meta.likes':{$gt:10}})

You need to query an array? No problem:

> db.articles.find({'meta.tags':'mongolia'})

When the key is an array, the database looks for the object right in the array.

You need to look for an object inside an array? No problemo:

> db.articles.find({'comments.by':'Steve'})

You can also refer to array indexes:

> db.articles.find({'comments.0.by':'Steve'})

Isn't that amazing?

Because of the fact that array objects can be matched using the dot notation, it can be problematic if the objects in an array share the same keys but different values. In such cases, we need to use the $elemMatch operator. To see an example and understand the issue better, read this.

Always remember that a quoted number is a string, and is not the same as the actual number. For example:

> db.students.find({score:100})

is totally different from

> db.students.find({score:'100'})

In general, form request parameters come as strings, so you are likely to be querying for the stringified version of numbers in your web apps if you use the parameters as such. Make sure to convert them to their number equivalent wherever necessary first. For example in Express, you can do this:

var score = +params.score;

params.score is a string, but score is now an actual JavaScript number, which can be reliably used in a MongoDB query.

MongoDB queries support JavaScript expressions! Take a look at this example:

> db.comedy.find('this.year > 1990 && this.name != "The School of Rock"')

does the same thing as:

> db.comedy.find({year:{$gt:1990}, name:{$ne:'The School of Rock'}})

But note that the flexibility of JavaScript expressions comes at a price - it is slower than native MongoDB operators.

MongoDB has another operator called $where using which you can perform SQL's WHERE-like operations.

> db.comedy.find({$where: 'this.year > 2000'})
{ "_id" : ObjectId("4ed45fae2274c776f9179f89"), "name" : "The School of Rock", "year" : 2003 }

and

> db.comedy.find({name:'The School of Rock', $where: 'this.year > 2000'})
{ "_id" : ObjectId("4ed45fae2274c776f9179f89"), "name" : "The School of Rock", "year" : 2003 }

Again, like JavaScript expressions $where is slower than native operators. Use JavaScript expressions and $where ONLY when you can't accomplish the query using native operators.

It is highly recommended that you go through all the advanced MongoDB query operators once you are done with this tutorial.

Update data in MongoDB


Let's try adding a new field for one of the documents. What comes to your mind instantly might look something like this:

> db.comedy.update({name:"Bill & Ted's Excellent Adventure"}, {director:'Stephen Herek'})

HOLD IT! That's about to do something disastrous. It will overwrite the whole document with {director:'Stephen Herek'}, instead of updating it by appending a new field.

The right way to do is:

> db.comedy.update({name:"Bill & Ted's Excellent Adventure"}, {'$set':{director:'Stephen Herek', cast:['Keanu Reeves', 'Alex Winter']}})

The above command will reorder the fields, but worry not, the data in safe and intact.

Now how do you update a value which is an array?

> db.comedy.update({name:"Bill & Ted's Excellent Adventure"}, {'$push':{cast:'George Carlin'}})
> db.comedy.update({name:"Bill & Ted's Excellent Adventure"}, {'$push':{cast:'Chuck Norris'}})

Eh, we need to remove something from the cast array. We do it this way:

db.comedy.update({name:"Bill & Ted's Excellent Adventure"}, {'$pull':{cast:'Chuck Norris'}})

As easy as that! But there's lot more to updating that just those, for details click here.

Delete data in MongoDB


How do you delete a field from a document?

> db.comedy.update({name:'Hulk'}, {$unset:{cast:1}})

In case you want to delete a field from all the document of a collection:

> db.comedy.update({$unset:{cast:1}}, false, true)

The false parameter if for upsert option, true is for multiple option. We set multiple option to true because we want to delete them all from the collection. In my opinion this is an inconsistency. It should work like find() and findOne(), when it comes to selection.

How do you delete a document from a collection?

> db.comedy.remove({name:'Hulk'})

In the above example, we deleted all the documents with their name field set as Hulk.

How do you empty a collection of its documents?

> db.comedy.remove()

Note, the above command does not delete the collection, it just 'resets' the collection like the SQL truncate command.

How do you delete / drop a collection?

> db.comedy.drop()

The above command actually deletes the collection.

To delete a database select the database and call the db.dropDatabase() on it:

> use movies
> db.dropDatabase()
{"dropped" : "movies", "ok" : 1 }

That deletes the database named movies.

Get the count of Documents / Records

Any good database system should have a count() method which returns the number of records that will be returned for a query. MongoDB too has a count() method which you can call on a collection to get the count of the results.

This will return the total number of documents in the collection named comedy:

> db.comedy.count({})

This will return the total number of documents in the collection named comedy with the value of year more than 1990:

> db.comedy.count({year:{$gt:1990})

So basically that's about it. There is a ton more to MongoDB than what I covered, I have listed the pointers at the Further Reading section, read all of them.

I hope you found this tutorial useful. I will be writing many more MongoDB related articles and tutorials in the future, so stay tuned. If you have any orientation / beginner level questions, feel free to ask me in the comments.

MongoDB Documentation

  1. MongoDB Manual
  2. Nightly generated PDF of the MongoDB Manual

Further Reading
  1. MongoDB Introduction
  2. SQL to Mongo Mapping Chart
  3. MongoDB Advanced Queries
  4. MongoDB Updating
  5. MongoDB Aggregation
  6. MongoDB Schema Design
  7. MongoDB Indexes
  8. MongoDB Cookbook
  9. MongoDB JavaScript API

18 Responses to “The MongoDB Tutorial”

  1. Trae R. says:

    This example is missing a closing bracket:
    db.articles.find({‘meta.author’:’Chad Muska’)

  2. Captain says:

    Thanks Trae, fixed.

  3. zhkzyth says:

    wow~~thanks for the straight forward explaination~ I just wonder if i need to read a mongodb book to write a “hello world” demo in mongodb….haha~~Thanks! you do a great job~

  4. Stanimir says:

    Thanks. Great tutorial. Just what I wanted to know. Thanks again.

  5. ken says:

    Thanks. Great job w/ this mongodb intro.

    I think the only thing I’d suggest is a Mongo Intro 102 that describes how you do typical data structures in MongoDB? E.g., how do you handle hierarchical data? What about references from one table to another (like when you do a many to many table in an RDBMS)? Something like a typical customer to order to item mapping would be a perfect example of all the issues you hit….so you can do stuff like “customer cancels item N” or “which customers ordered item N”.

  6. manu says:

    FYI, the last example misses a ‘}’

  7. Jaya says:

    Thanks much, that was great :)

  8. sayali says:

    Very helpful tutorials!!!!
    thanks!!!

Make a Comment