NoSQL databases came back into the mainstream when developers needed better performance and were ok with giving up the relational aspect of RDBs (unions, joins, etc). NoSQL is said to be easily scalable horizontally, unlike SQL databases. To use the NoSQL datastore MongoDB with your node instance, you need to install:

MongoDB – http://www.mongodb.org/display/DOCS/Quickstart

node-mongodb-native driver – http://www.mongodb.org/display/DOCS/node.JS

mongoose (optional but strongly encouraged and used here) – http://mongoosejs.com/

The mongoDB schema is dynamic, meaning it gets defined every single time you launch your node server.

So to begin, this is how you define a schema:

var Schema = mongoose.Schema , ObjectId = Schema.ObjectID; var Hobby = new Schema({ name : { type: String, required: true, trim: true } }); var Person = new Schema({ first_name : { type: String, required: true, trim: true } , last_name : { type: String, required: true, trim: true } , username : { type: String, required: true, trim: true } , hobbies : [Hobby] , shoe_size : Number , eye_color : String });

Where Schema is a mongoose interface and ObjectId is a MongoDB datatype. Inside Person (called a collection) you can see the different ways you can define SchemaTypes. The [Hobby] is an array or collection of Embedded Documents (which is itself a Schema, must be defined prior to the main schema). Mongoose also comes with validation middleware, so this acts as your server-side data validation (opposed to client side js).

function validateThis(v){ return v == 'mike'; } ... first_name : { type: String, required: true, trim: true, validate: [validateThis, 'your name isnt mike'] } ...

Useful reading on Injection in MongoDB.

And to be able to modify Person we need:

var Person = mongoose.model('Person', Person);

And thats about it for designing schemas!

To save/insert data to a schema, we use the .save() function, which has a callback (as all other db interaction calls).

var person_data = { first_name: req.params.first , last_name: req.params.last , username: req.params.username }; var person = new Person(person_data); person.save( function(error, data){ if(error){ res.json(error); } else{ res.json(data); } });

So person_data is the data we have and want to insert, and as you can see it matches the minimum requirements. After creating a new person object, we can save it to the database. By default, the callbacks have an error and data parameters. They return null by default – no error and no data.

To retrieve some data:

Person.find({}, function(error, data){ console.log(data); res.json(data); });

Where the first parameter of .find() can be a json object such as

{ username: 'mike' }

which acts as

WHERE username="mike"

(mongoose reference).

And to update a document within a collection, I chose to first check to see if there are actually any users with this username. Then we use the callback parameter

person

which is the actual document with username match to perform alterations and save it. There are other ways to do this.

Person.findOne({ username: req.params.username }, function(error, person){ if(error){ res.json(error); } else if(person == null){ res.json('no such user!') } else{ person.hobbies.push({ name: req.params.hobby }); person.save( function(error, data){ if(error){ res.json(error); } else{ res.json(data); } }); } });

I think that’s about it, pull or copy/paste the git repo. Let’s start the server:

node app.js

And add a single document by going to the url:

localhost:3001/adduser/michael/mukhin/mmukhin

To view all documents, go to:

localhost:3001/

And to add hobbies to any user:

localhost:3001/addhobby/mmukhin/beer

GIT repo: https://github.com/mmukhin/psitsmike_mongodb_tutorial

Additional reading: NoSQL server-side javascript injection.