Skip to content

Instantly share code, notes, and snippets.

@alemohamad
Last active August 29, 2015 14:17
Show Gist options
  • Save alemohamad/65154bd659786087a31b to your computer and use it in GitHub Desktop.
Save alemohamad/65154bd659786087a31b to your computer and use it in GitHub Desktop.
Personal notes from the MongoDB University course "M101JS: MongoDB for Node.js Developers".

Install ExpressJS

$ npm install express

Install Consolidate & Swig (templates)

$ npm install consolidate
$ npm install swig

Install MongoDB Node driver

$ npm install mongodb

MongoDB Schema Design

Multikeys

> db.students.ensureIndex({ 'teachers' : 1 })
> db.students.find({ 'teachers': { $all: [0,1] } })
> db.students.find({ 'teachers': { $all: [0,1] } }).explain()

Some MongoDB commands

Display all DBs

> show dbs

Create and use a DB

> use demo

Find something

> db.things.find()

or

> db.things.find().pretty()

At the database db (in this case "demo"), get the collection things, find all the documents in this collection.

If you do call the find() method, and there's a lot of data, the database return the results in batches (of like 20 results). To continue the iteration and get the other results, MongoDB offers the command it (iteration).

You can also find a collection that has an object (like a filter in your query). This is called a "query by example".

> db.things.find({ "a": 1 })

To add a filter and get a range of results, you can do the following:

> db.things.find({ "a": { $gt: 90 } }) // greater than 90
> db.things.find({ "a": { $lte: 35 } }) // lesser than and equal 35
// options are "gt", "lt", "gte" and "lte"

> db.people.find( { name : { $lt : "D", $gt : "B" } } )
// This is to get names that starts with a C and before (not with "D")
// and names that starts with a B (included, because "Bob" is greater than "B", because it has more characters)

// more complicated searches
> db.people.find( { profession : { $exists : true } } ); // records that has the selected field
> db.people.find( { profession : { $type : 2 } } ); // records that has the type of field (BSON specification http://bsonspec.org/)
> db.people.find( { name : { $regex : "a" } } ) // regex: fields that has an "a"
> db.people.find( { name : { $regex : "e$" } } ) // regex: fields that ends with an "e"
> db.people.find( { name : { $regex : "^A" } } ) // regex: fields that starts with an "A"

You can search for two different queries (one filter or another):

> db.people.find( { $or : [ { name : { $regex : "e$" } }, { age : { $exists : true } } ] } );
// $or it has to be at the begginig of the desired queries

Also you can do the and query (but the JSON document creation already does that, right?):

> db.people.find( { $and : [ { name : { $gt : "C" } }, { name : { $regex : "a" } } ] } );

When doing a search, and want to do a find of a field that has a string, that is inside an array:

> db.people.insert( { name : "John", shirts : [ "red", "white", "black" ] } );
> db.people.find( { shirts : "white" } ); // it's going to return the inserted record, because at the first level of the array it found the value "white"
// also you can search for more than one item inside an array, with the $all option
> db.people.find( { shirts : { $all : [ "red", "black" ] } } );
// also you can search inside a value that is or isn't an array with the $in option (this is at least one of the search terms, not necessary every one of them)
> db.people.find( { name : { $in : [ "Howard", "John" ] } } );

When you try to find a single document, you can use findOne.

> db.things.findOne() // returns a random document
> db.things.findOne({ "name": "John" }) // returns one random document that has the name "John"
> db.things.findOne({ "name": "John" }, { "name": true, "_id": false }) // to specify the fields I want and don't want to be returned, it also works with .find()

Dot Notation

If you have a document inside a document, you can search with the little thing called Dot Notation. This is handful, because you can't search with a piece of the object like we did before.

> db.people.find( { "email.work" : "[email protected]" } );

Cursors

When you read the hole collection, and saved it in a variable, you can iterate through each one of the documents, in the following way:

> cur = db.things.find();
> cur.hasNext(); // returns true
> cur.next(); // returns the next result
> while (cur.hasNext()) printjson(cur.next()); // iterate through all of them by code

Another thing to do with this is limit the results:

> cur = db.things.find();
> cur.limit(5);

Also we can sort the results:

> cur = db.things.find();
> cur.sort( { name : -1 } );

And (as you already suppose) you can skip some results:

> cur = db.things.find();
> cur.skip(2);

You can also mix these methods!

> cur = db.things.find();
> cur.sort( { name : -1 } ).limit(3).skip(2);

Insert an object in a collection

> db.things.insert({"a": 1, "b": 2, "c": 3})

or

> db.things.save( { a: 1, b: 1, fruit: ["apple", "orange", "banana"] } )

Count elements

> db.people.count( { type : "student" } )

Because MongoDB is based in Javascript, we can do JS operations

> for (var i = 0; i < 10; i++) { db.things.insert({ "x" : i }) }

Edit an item

var item = db.users.findOne({ 'name': 'Ale Mohamad' })
item.code_language = 'NodeJS'
db.users.save(item)

mongorestore

If you have a mongodb dump, and you want to add that base in your current mongodb server, you have to do:

$ mongorestore <folder-with-dumps>

CRUD terminology

  • Create => Insert
  • Read => Find
  • Update => Update
  • Delete => Remove

Update documents

With the following example, you can search for documents that have the name "Smith", and update that documents with the name "Thompson" and salary "50000". The bad thing is that if the selected documents have more fields, they will be discarded, and deposit only the information of the second group.

> db.people.update( { name : "Smith" }, { name : "Thompson", salary : 50000 }) // this is dangerous

This is a safer method:

> db.people.update( { name : "Smith" }, { $set : { age : 30 } } )
// also, you can find a document, and increment the value of one of the fields
> db.people.update( { name : "Smith" }, { $inc : { age : 1 } } )

And if you want to remove a field from the document:

> db.people.update( { name : "Smith" }, { $unset : { age : 1 } } )

To manipulate a preexistent array inside a document, you can do the following:

> db.people.update( { name : "Smith" }, { $push : { "favorites" : "Hockey" } } ) // add to the right
> db.people.update( { name : "Smith" }, { $pop : { "favorites" : 1 } } ) // remove 1 element from  the right
> db.people.update( { name : "Smith" }, { $pop : { "favorites" : -1 } } ) // remove 1 element from  the left
> db.people.update( { name : "Smith" }, { $pushAll : { "favorites" : [ "Hockey", "Golf", "Tennis" ] } } ) // add to the right
> db.people.update( { name : "Smith" }, { $pull : { "favorites" : "Hockey" } } ) // remove the defined element
> db.people.update( { name : "Smith" }, { $pullAll : { "favorites" : [ "Hockey", "Tennis" ] } } ) // opposite of $pushAll
> db.people.update( { name : "Smith" }, { $addToSet : { "favorites" : "Hockey" } } ) // adds to the set, but if that item is already there, it doesn't add it again

If you'd like to use update() on a document that doesn't exists, you can do it with upsert, and create it:

> db.people.update( { name : "George" }, { $set : { age : 40 } }, { upsert : true } )

We can update every document of the table, using the multi property, and the search field with an empty document:

> db.people.update( { }, { $set : { title : "Dr" } }, { multi : true } )

Remove documents

> db.people.remove( { name : "Alice" } ) // this remove only one document
> db.people.remove( { } )
> db.people.drop() // this is faster, because it doesn't have to remove each one of the results

An example of how to insert a lot of random information

> for (i=0; i<1000; i++) { names=["exam", "essay", "quiz"]; for (j=0;j<3;j++) { db.scores.insert( { "student" : i, "type" : names[j], score : Math.round(Math.random()*100) } ); } }

Import a JSON file to a MongoDB database

$ mongoimport -d course -c grades grades.json

Import a CSV file to a MongoDB database

$ mongoimport --type csv --headerline weather_data.csv -d weather -c data

Install MongoDB locally (Mac)

Instructions at https://www.mongodb.org/downloads.

$ tar xvf mongodb-osx-x86_64-3.0.1.tgz

Create the data folder for MongoDB:

$ sudo mkdir -p /data/db
$ sudo chmod 777 /data
$ sudo chmod 777 /data/db

Move the files from mongodb-osx-x86_64-3.0.1/bin to the /usr/local/bin/ folder:

$ cd mongodb-osx-x86_64-3.0.1/bin
$ cp * /usr/local/bin

Now you can create an instance of the MongoDB local server:

$ mongod

In another bash window you can open a client to access the Mongo Shell (it works as an usual web console):

$ mongo

We can get some help, as in

> help keys
Tab completion and command history is available at the command prompt.

Some emacs keystrokes are available too:
  Ctrl-A start of line
  Ctrl-E end of line
  Ctrl-K del to end of line

Multi-line commands
You can enter a multi line javascript expression.  If parens, braces, etc. are not closed, you will see a new line
beginning with '...' characters.  Type the rest of your expression.  Press Ctrl-C to abort the data entry if you
get stuck.

How to do a mongodb query

db.collection('grades').findOne(query, function(err, doc) {
  // do the stuff with the doc variable
});
var query = { "grade" : 100 };

var cursor = db.collection('grades').find(query);

cursor.each(function(err, doc) {
  // do the stuff with the doc variable
});
var query = { "grade" : 100 };

// this is to filter the fields that are going to be returned (only student, and not _id)
var projection = { "student" : 1, "_id" : 0 };

db.collection('grades').find(query, projection).toArray(function(err, docs) {
  // do stuff with the docs variable
});
var query = { "student" : "Joe", "grade" : { "$gt" : 80, "$lt" : 95 } };

db.collection('grades').find(query).each(function(err, doc) {
  // do stuff with the doc variable
});

Import an external JSON file to MongoDB

var MongoClient = require('mongodb').MongoClient
  , request = require('request');

MongoClient.connect("mongodb://localhost:27017/course", function(err, db) {
  if(err) throw err;
  
  request('http://www.reddit.com/r/technology/.json', function(error, response, body) {
    if (!error && response.statusCode == 200) {
      var obj = JSON.parse(body);
      
      var stories = obj.data.children.map(function(story) { return story.data; });
      
      db.collection('reddit').insert(stories, function(err, data) {
        if(err) throw err;
        
        console.dir(data);
        
        db.close();
      });
    }
  });
});

Skip, limit and sort in Express (NodeJS)

var grades = db.collection('grades');

var cursor = grades.find({});
cursor.skip(1);
cursor.limit(4);
cursor.sort([['grade', 1], ['student', -1]]);
var grades = db.collection('grades');

var options = { 'skip': 1,
                'limit': 4,
                'sort': [['grade', 1], ['student', -1]]
};

var cursor = grades.find({}, {}, options);

Insert a document in NodeJS

var doc = { 'student' : 'Calvin', 'age' : 6 };

db.collection('students').insert(doc, function(err, inserted) {
  // do stuff with inserted var
});

Update a document in NodeJS

var query = { 'assignment' : 'hw1' };

db.collection('grades').findOne(query, function(err, doc) {
  query['_id'] = doc['_id'];
  doc['date_returned'] = new Date();
  
  db.collection('grades').update(query, doc, function(err, updated) {
    // do stuff with updated var
  });
});

Another way:

var query = { 'assignment' : 'hw1' };
var operator = { '$set' : { 'date_returned' : new Date() } };

db.collection('grades').update(query, operator, function(err, updated) {
  // do stuff with updated var
});

And another way:

var query = { 'assignment' : 'hw1' };
var operator = { '$unset' : { 'date_returned' : '' } };
var options = { 'multi' : true };

db.collection('grades').update(query, operator, options, function(err, updated) {
  // do stuff with updated var
});

Update / create a document with upserts

var query = { 'student' : 'Frank', 'assignment' : 'hw1' };
var operator = { '$set' : { 'date_returned' : new Date(), 'grade' : 100 } };
var options = { 'upsert' : true };

db.collection('grades').update(query, operator, options, function(err, upserted) {
  // do stuff with upserted var
});

Another way to do an upsert, but without saying its an upsert.

var query = { 'assignment' : 'hw2' };

db.collection('grades').findOne(query, function(err, doc) {
  if(err) throw err;
  
  doc['date_returned'] = new Date();
  
  db.collection('grades').save(doc, function(err, saved) {
    // do stuff with saved var
  });
});

Find and Modify

db.collection('homeworks').findAndModify({}, [[ 'grade' , 1 ]], { '$set' : { 'dropped' : true } }, { 'new' : true }, callback); 

Delete documents

var query = { 'assignment' : 'hw3' };

db.collection('grades').remove(query, function(err, removed) {
  // do stuff with removed var
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment