Chapter 8

MongoDB

In this chapter, you first discover the advantages of NoSQL databases and why so many new projects are using them. Then you find out how to install MongoDB, along with a native MongoDB driver for Node.

Next you learn how to use the MongoDB driver to create a database. You also find out how to read entries from the database using MongoDB's robust query options, such as regular expressions and operators. Furthermore, you learn how to update and delete database entries, completing the CRUD system.

After determining how to use the native MongoDB driver, you learn about Mongoose, an object modeling package for Node and MongoDB. Mongoose provides the familiar ability to save data in models and then sync these models to a MongoDB server, much like you do with Backbone in Chapter 3. Finally, you find out about other database modules for Node, such as the MySQL module and another NoSQL database called Redis.

What's So Good About NoSQL?

For a good 30 years, the dominant model for database design has been relational databases such as MySQL. However, a recent trend is moving away from conventional relational database models. This trend is known as NoSQL (or Not Only SQL). Non-relational, NoSQL databases are an attractive alternative for a variety of reasons, mainly scalability and simplicity. Considering that Node.js projects often share the same goals, it makes sense that many use a NoSQL database.

Scalability

One of the main reasons to use a NoSQL database like MongoDB is its built-in sharding capabilities. Sharding allows you to distribute a single database across a cluster of machines, which means you can scale out (distribute the load) rather than scale up (purchase a larger server). Scaling horizontally complements the cloud model, since your NoSQL cloud can ramp up resources as needed to handle load, as opposed to having one really powerful server that sits unused for long periods of time.

Beyond load, sharding also helps the server handle big data. The volume of data stored in databases is increasing exponentially, to the point that some databases are too large for an individual server. With these databases, distribution across a cluster becomes a necessity. Traditional relational databases on the other hand were built before we ever had the need to work with large-scale data. It's not impossible to distribute a database like MySQL, but it is significantly more challenging than distributing a database that was designed to be sharded.

Simplicity

Part of the reason NoSQL databases scale so well is that they were built from the ground up for simplicity. Besides sharding, this simplicity also brings additional advantages. Mainly, NoSQL databases are a lot easier to manage thanks to administration tools that solve many of the admin problems we face today. These tools allow many NoSQL implementations to forgo the army of database administrators (DBAs) that is commonly associated with relational databases. Of course, this simplicity comes at the price of functionality. But if you need relatively simple features in your database software, non-relational databases can't be beat.

Getting Started with MongoDB

MongoDB is a NoSQL database that is very popular for Node development. Fortunately, getting started with MongoDB is relatively easy. In this section you learn how to install MongoDB along with a couple drivers for Node. Then you run the database server and create your first database.

Installing MongoDB

Before you can use MongoDB, you have to install it. Unlike other Node modules, the MongoDB module is only a driver. That means you'll have to install MongoDB on your system before you use it.

Mac Installation

The easiest way to install MongoDB on Mac is by using a package manager like MacPorts or Homebrew. If you're using MacPorts (http://www.macports.org/install.php), simply type the following command:

sudo port install mongodb

Likewise, if you're using Homebrew (http://mxcl.github.com/homebrew), type the following:

sudo brew install mongodb

Alternatively, you can install MongoDB yourself. First, download the tarball from http://downloads.mongodb.org/osx/mongodb-osx-x86_64-2.2.2.tgz and extract the contents. Then set up the PATH variable to wherever you extracted the MongoDB core—that way, you can use its commands easily. Add the MongoDB directory to the PATH declaration in ~/.bash_profile.

Regardless of how you install MongoDB on Mac, you'll also need to set up the data directory:

sudo mkdir -p /data/db

sudo chown `id -u` /data/db

These commands set up the directory with the appropriate permissions.

There's a nice GUI tool for Mac called MongoHub, which you can download from http://mongohub.todayclose.com. This tool, shown in Figure 8-1, helps you manage the database.

MongoHub is great for managing complex aspects of a database, when you don't want to bother to learn how to do so with the API. It also provides a monitor you can use to view activity on a database in real time.

9781118524404-fg0801.eps

Figure 8-1 The MongoHub GUI tool for Mac.

Ubuntu Installation

First, to authenticate the apt-get package, install the public GPG key from the MongoDB creators:

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10

Next create a file called /etc/apt/sources.list.d/10gen.list, and add the following text:

deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen

Then back in the terminal, reload your repository and install the latest stable build of MongoDB:

sudo apt-get update

sudo apt-get install mongodb-10gen

Windows Installation

First, download the latest stable build from http://www.mongodb.org/downloads. Make sure to get the appropriate version for your Windows install (64-bit or 32-bit). Extract the contents of that file and move it to C:mongodb. You can move it from the Window's Command Prompt:

cd

move C:mongodb-win32-* C:mongodb

Finally, create the data directory for MongoDB:

md data

md datadb

MongoDB has installation instructions for other operating systems in its docs. Visit http://docs.mongodb.org/manual/installation for information.

Running MongoDB

After installing MongoDB, you're ready to run it. You can do so using the following command in Mac:

mongod

Or in Ubuntu, use

sudo service mongodb start

Or in Windows, run the .exe file from the Command Prompt:

C:mongodbinmongod.exe

If you see some output in the terminal and the command is still running, you'll know that everything is working. See Figure 8-2.

9781118524404-fg0802.tif

Figure 8-2 If your terminal looks like this, MongoDB is running.

If you're having trouble getting the mongod command to work, make sure MongoDB has been added to your PATH variable. Package managers will handle that automatically, but you must set it up manually if you installed MongoDB yourself.

Installing MongoDB Modules

Once MongoDB is running on your system, you need to install a module to communicate with the database. In this chapter, you learn how to use two different modules:

The MongoDB Native Node.js Driver: Basic MongoDB support in JavaScript

Mongoose: An object modeling tool that provides object-relational mapping (ORM)

But for now, just install the native driver using NPM:

npm install mongodb

Creating a Database

Once MongoDB is running and the Node.js driver is installed, you're ready to create a database. First, require the MongoDB module in Node:

var mongodb = require('mongodb'),

Then create a new database:

var dbServer = new mongodb.Server('localhost', 27017, {auto_reconnect:

true}),

var db = new mongodb.Db('mydb', dbServer, {w: 1});

A few things are going on here:

1. new mongodb.Server(‘localhost', 27017, {auto_reconnect: true}), connects to the MongoDB server. It uses the default host (localhost) and default port (27017). auto_reconnect allows it to reconnect automatically if the connection is interrupted.

2. new mondodb.Db() creates a new database, in this case called mydb. If this database already exists, it simply references the existing database.

3. The third argument of mongodb.Db(), {w: 1}, sets the write concern, indicating that this is the primary mongod instance. This works just fine so long as you don't have more than one instance of MongoDB on your server. But if you'd like to learn more about other options, visit http://docs.mongodb.org/manual/core/write-operations/#write-concern.

If you need to authenticate your database, you can do so using db.authenticate(user, password, function() { /* callback */ }).

CRUD with MongoDB

In this section, you find out how to use CRUD in MongoDB to create, read, update, and delete documents. These four operations represent the basic needs of any persistent storage system, such as a database.

So far you've included the MongoDB module, and created a new database. However, if you look at the server on MongoHub or another GUI tool, you'll see that the database doesn't exist. That's because you still need to add collections before it will be created.

MongoDB is a document-based database, so entries are called documents.

Creating Collections

Whereas other databases, such as MySQL, represent data using tables, MongoDB uses collections, which are represented with simple JSON objects. As a JavaScript developer, that should be music to your ears. But before adding a collection, you first need to connect to the database, using the db variable defined earlier:

db.open( function(err, conn) {

});

Here you can see a familiar pattern in Node: an asynchronous callback, with an error object as the first argument.

Adding a Collection

Next, in this callback, add a collection to the database:

db.open( function(err, conn) {

  // add a collection to the db

  db.collection('myCollection', function(err, collection) {

    // insert a document into the collection

    collection.insert({

      a: 'my item'

    }, function(err, result) {

      // log the result

      console.log(result);

      

      // close the connection

      db.close();

    });

  });

});

Here's what's going on:

1. db.collection() creates a new collection called myCollection.

2. In the next callback, a document is added to the collection using collection.insert(). This uses the collection object that is passed into the callback. As you can see, the structure of the insert is a simple JSON object, {a: ‘my-item'}.

3. Finally, in the callback for the insert, the result is logged to the console, and the database connection is closed with db.close(). Don't forget to close the MongoDB connection when you finish using it.

Now run the script in Node. Figure 8-3 shows the database and collection created.

9781118524404-fg0803.eps

Figure 8-3 MongoHub shows the new database and collection.

To make the example shorter, I avoided catching any of the errors. But you should use console.log() to find errors if you're having problems with this script.

The Unique Identifier

When you run this script, you may notice in the Node console that the database entry doesn't wind up as simple as {a: ‘my item'} (see Figure 8-4). That's because MongoDB added an identifier, _id, to the document. MongoDB needs these unique identifiers for everything stored in the database, so by default, it will add them automatically whenever you create new documents.

9781118524404-fg0804.tif

Figure 8-4 The result of the database entry in the console.

But, as you can see, the identifiers are pretty long and unwieldy. Although they work well for MongoDB internally, you usually want to avoid using them to reference the documents in your database. Just as with other databases, it's a good idea to add your own key when you need to reference an identifier— for instance, {id: 1}.

Reading Data

After adding documents to the database, you can read them using find(). This API provides a number of useful selection capabilities, allowing you to select specific documents, leverage query selectors, and sort the data that is returned.

But before using the find() API, create a new collection to work with:

// open database connection

db.open( function(err, conn) {

  // select the collection

  db.collection('myNewCollection', function(err, collection) {

    // cache a count variable

    var count = 0;

    

    // insert numbers into the collection

    for ( var i = 0; i < 5; i++ ) {

      collection.insert({

        num: i

      }, function(err, result) {

        // log the result

        console.log(result);

        

        // increment the count value

        count++;

        

        // if the count is high enough, close the connection

        if ( count > 4 ) {

          db.close();

        }

      });

    }

  });

});

This script creates a new collection called myNewCollection and adds five new documents to it in a loop.

Here you can see an important pattern in Node development. Even though the script uses a for loop with an increment, it can't use that same increment to determine when to close the database connection. That's because all of the Node calls are asynchronous. As you may have noticed in the output, the different collection.insert() statements fired in a fairly random order:

[ { num: 0, _id: 50dc93c946f8df0000000001 } ]

[ { num: 4, _id: 50dc93c946f8df0000000005 } ]

[ { num: 3, _id: 50dc93c946f8df0000000004 } ]

[ { num: 2, _id: 50dc93c946f8df0000000003 } ]

[ { num: 1, _id: 50dc93c946f8df0000000002 } ]

However, it's still important to close the database connection at the right time. If you use the increment from the for loop, it will most likely close the connection too early (which will, in turn, reopen the connection in the next insert(), and then leave it open). To get around this issue, the script uses a separate count value, which is incremented as each asynchronous call completes. Once this value is high enough, you can safely close the connection.

Selecting All Entries in a Collection

Now that a collection has been created, you can select all the data in the database:

db.open( function(err, conn) {

  // select the collection

  db.collection('myNewCollection', function(err, collection) {

    // select all the documents in the collection

    collection.find().toArray(function(err, result) {

      // log the data

      console.log(result);

      

      // close the connection

      db.close();

    });

  });

});

This script selects the collection that was created earlier and then uses collection.find() to select all the documents in the collection. As you can see, all the entries are output to the console:

[ { num: 0, _id: 50dc93c946f8df0000000001 },

  { num: 1, _id: 50dc93c946f8df0000000002 },

  { num: 2, _id: 50dc93c946f8df0000000003 },

  { num: 3, _id: 50dc93c946f8df0000000004 },

  { num: 4, _id: 50dc93c946f8df0000000005 } ]

You may have noticed that the documents in this collection are now in the correct order, although you just saw them being inserted out of order. Even though the asynchronous insertion calls completed at different times, MongoDB's IDs are still in the correct order.

Selecting Specific Entries

Since you didn't pass any arguments into collection.find(), it selected all the documents in the database. But you can also select specific documents. For example:

db.collection('myNewCollection', function(err, collection) {

  // select all documents where num is 2

  collection.find({num: 2}).toArray(function(err, result) {

    // log the data

    console.log(result);

    

    // close the connection

    db.close();

  });

});

This script selects the document with a num value of 2, as seen in the output here:

[ { num: 2, _id: 50dc93c946f8df0000000003 } ]

Because only one document has a num value of 2, the preceding search returned only one value. If there were more than one match, it would return an array of all the matching documents.

More Advanced Query Selectors

You can also use more advanced selectors. For example, to select all values that are greater than 1, use the $gt operator:

// select the collection

db.collection('myNewCollection', function(err, collection) {

  // select numbers greater than 1

  collection.find({num: {$gt: 1}}).toArray(function(err, result) {

    // log the data

    console.log(result);

    

    // close the connection

    db.close();

  });

});

Here the script passes in a query object, {$gt: 1}, for the num value to match against, which selects all values that are greater than 1, as shown in this output:

[ { num: 2, _id: 50dc93c946f8df0000000003 },

  { num: 3, _id: 50dc93c946f8df0000000004 },

  { num: 4, _id: 50dc93c946f8df0000000005 } ]

You can combine additional parameters in the query object. For instance, you can match all values that are greater than 1 but also less than 4:

db.collection('myNewCollection', function(err, collection) {

  // select numbers greater than 1 but less than 4

  collection.find({num: {$gt: 1, $lt: 4}}).toArray(function(err, result) {

    // log the data

    console.log(result);

    

    // close the connection

    db.close();

  });

});

This script adds a $lt operator to pull values that are also less than 4, as shown here:

[ { num: 2, _id: 50dc93c946f8df0000000003 },

  { num: 3, _id: 50dc93c946f8df0000000004 } ]

For a full list of the operators you can use in the query object, visit http://docs.mongodb.org/manual/reference/operators.

You can even use regular expressions to select particular strings in MongoDB. Simply pass the regex into the selector; for example, you can select all names that start with “a” using collection.find({name: /^a/}).

Limiting Entries

You can also limit the number of documents the search returns:

db.collection('myNewCollection', function(err, collection) {

  // select all the data in the collection, limited to 3 entries

  collection.find({}, {limit: 3}).toArray(function(err, result) {

    // log the data

    console.log(result);

    

    // close the connection

    db.close();

  });

});

Here a second argument is passed to collection.find(), which defines additional information about the search. In this case, {limit: 3} limits the search to return at most three documents, as shown in this output:

[ { num: 0, _id: 50dc93c946f8df0000000001 },

  { num: 1, _id: 50dc93c946f8df0000000002 },

  { num: 2, _id: 50dc93c946f8df0000000003 } ]

You can also use findOne() instead of find() as a shorthand to return a single document.

Sorting Entries

Additionally, you can sort the documents in the collection when selecting them.

db.collection('myNewCollection', function(err, collection) {

  // sort the collection in reverse order

  collection.find({}, {sort:[['num', 'desc']]}).toArray(function(err, result) {

    // log the data

    console.log(result);

    

    // close the connection

    db.close();

  });

});

Here the script defines a sort parameter, which sorts by the num field, in descending order. This sort parameter accepts an array, which means that you can sort by multiple columns as needed. You also can combine it with limit values. You can see the result here:

[ { num: 4, _id: 50dc93c946f8df0000000005 },

  { num: 3, _id: 50dc93c946f8df0000000004 },

  { num: 2, _id: 50dc93c946f8df0000000003 },

  { num: 1, _id: 50dc93c946f8df0000000002 },

  { num: 0, _id: 50dc93c946f8df0000000001 } ]

Updating Data

So far you know how to handle the C and R of CRUD; now let's talk about the U. In this subsection you discover a variety of techniques for modifying the existing documents in your database. You learn how to select particular documents for updating, as well as how to take advantage of special update methods such as upsert and find and modify.

Updating an Entire Entry

To update a value, simply use the update() method:

db.collection('myNewCollection', function(err, collection) {

  // update one of the documents

  collection.update({num: 2}, {num: 10}, {safe: true}, function(err) {

    if (err) {

      console.log(err);

    }

    else {

      console.log('Successfully updated'),

    }

    

    db.close({});

  });

});

As you can see, collection.update() accepts four arguments:

The criteria for the update, meaning a query for which documents to update —In this case, it will update all entries with a num value of 2. This can also use any of the advanced query operators you learned about with find(). For instance, to update all num values less than 2, you pass {num: {$lt: 2}}.

The changes you want to make —In this case, the num value is changed to 10.

An options object —Here {safe: true} sets safe mode, which you should probably always use. Another useful option is {multi: true}, which allows the update to modify multiple documents.

An optional callback —You can use this to output any error that occurs.

Upserting

You can also upsert values into your collection, which updates the document if it exists; otherwise it inserts a new document with the values you're updating. To use upsert, simply set {upsert: true} in the options object:

db.collection('myNewCollection', function(err, collection) {

  // upsert one of the documents

  collection.update({num: 8}, {num: 7}, {safe: true, upsert: true}, function(err) {

    if (err) {

      console.log(err);

    }

    else {

      console.log('Successfully updated'),

    }

    

    db.close({});

  });

});

Here, even though a document matching {num: 8} can't be found in the collection, a new document with {num: 7} is inserted. Had the {num: 8} entry existed, MongoDB would have simply updated that document.

Setting a Particular Field

The previous examples all update the entire document, but you can also update an individual field using the $set modifier:

db.collection('myNewCollection', function(err, collection) {

  // set an individual field

  collection.update({num: 3}, {$set: {desc: 'favorite number'}}, {safe: true}, function(err) {

    if (err) {

      console.log(err);

    }

    else {

      console.log('Successfully updated'),

    }

    

    db.close({});

  });

});

Here, instead of passing an object for the second argument, the script uses a $set modifier. That sets the desc field of the document, while preserving any existing fields.

For information about other MongoDB update modifiers, visit http://docs.mongodb.org/manual/applications/update.

Find and Modify

Finally, you can use a special API if you want to do anything with the document you're updating. If that's the case, use findAndModify(), which returns the affected document in the callback. However, be careful because the API signature is slightly different; it inserts an additional argument after the first:

db.collection('myNewCollection', function(err, collection) {

  // find and modify

  collection.findAndModify({num: 4}, [['_id', 'asc']], {num: 25}, {safe: true}, function(err, result) {

    if (err) {

      console.log(err);

    }

    

    // log the affected document

    else {

      console.log(result);

    }

    

    db.close({});

  });

});

As you can see here, findAndModify() accepts five arguments:

• The criteria for the search, {num: 4}

• The sort order (this argument doesn't exist in update()), [[‘_id', ‘asc']]

• The change you want to make, {num: 25}

• An options object, {safe: true}

• The callback function, which also passes the result of the query, function() { ... }

Another caveat of using findAndModify() is that the callback returns the document as it stood before the modification. For example, in this case, findAndModify() returns {num: 4} instead of the new {num: 25}, which you can see in this output:

{ _id: 50dc93c946f8df0000000005, num: 4 }

Deleting Data

Lastly, you still need to know the D in CRUD before your knowledge of MongoDB is complete. This subsection teaches you how to remove documents and collections from your database.

Removing Documents

First, you can delete documents from a collection using remove(). remove() is pretty straightforward; you just pass in the criteria of the documents you want to remove, followed by a callback:

db.collection('myNewCollection', function(err, collection) {

  // remove a document

  collection.remove({num: 1}, function(err) {

    if (err) {

      console.log(err);

    }

    else {

      console.log('Successfully removed'),

    }

    

    db.close({});

  });

});

If you want to do anything with the entry you're removing, use findAndRemove(). However, be careful—just like with findAndModify(), a sort argument has been added to the API:

db.collection('myNewCollection', function(err, collection) {

  // find and remove

  collection.findAndRemove({num: 0}, [['_id', 'asc']], function(err, result) {

    if (err) {

      console.log(err);

    }

    

    // log the affected document

    else {

      console.log (result);

    }

    

    db.close({});

  });

});

This works exactly like remove(), except that a second argument for sort order is added. Additionally, the result of the query is passed to the callback, which allows you to output the document as it existed before deletion.

Dropping Collections

You can also delete an entire collection. To do so, use db.dropCollection():

// open database connection

db.open( function(err, conn) {

  // drop a collection

  db.dropCollection('myNewCollection', function(err, result) {

    if (err) {

      console.log(err);

    }

    else {

      console.log(result);

    }

    

    db.close();

  });

});

This script drops the collection you've been working with. But be careful; as with all the database changes in this chapter, there's no magical undo button.

Mongoose

Mongoose is an object-modeling tool for Node that connects to MongoDB. You're already familiar with Backbone, so using Mongoose will be a piece of cake, because Mongoose models data similarly to Backbone, with models and collections. Mongoose then takes these models and maps them to a MongoDB database, saving you a lot of extra leg work.

This section teaches you how to install Mongoose and create models to store data. You then learn techniques for reading the data and how to select specific documents and fields from those documents.

Getting Started with Mongoose

Installing Mongoose is easy with NPM:

npm install mongoose

After Mongoose and its dependencies install, include it in Node:

var mongoose = require('mongoose'),

Next connect to a MongoDB database:

mongoose.connect('localhost', 'mydb'),

Here Mongoose will connect to the database mydb on localhost.

You may have noticed that the connect() call doesn't include a callback. That's because you have to set up these callbacks manually:

// connect to a MongoDB database

mongoose.connect('localhost', 'test'),

// database connection

var db = mongoose.connection;

// error callback

db.on('error', function(msg) {

  console.log(

    'Connection Error: %s', msg

  );

});

// success callback

db.once('open', function callback () {

  // on success

  console.log('Database opened succesfully'),

});

This script first creates a connection object and then binds two callbacks: One to fire on any connection error and another to fire once when the connection is successfully opened.

Pretty much everything you do in Mongoose will exist in the success callback. For the sake of brevity, I've omitted it from the following examples, but just assume that all of the code exists in this callback.

Creating Models

You use models to define all the documents in Mongoose. Models allow you to abstract away the database system and focus on what you really want: the data. In this section you learn how to create a schema to define the structure of a model, and then create and save models according to that structure.

Creating a Schema

The first step to creating a model is creating a schema to define the data types and structure that the model will use. For example, create a schema for different types of fruit:

// define the schema

var fruitSchema = mongoose.Schema({

  name: String,

  color: String,

  quantity: Number,

  ripe: Boolean

});

Here a schema is defined with different fields, setting a primitive data type for each.

You can also set more information along the schema by passing an object instead of a primitive, as in this example:

// define the schema

var fruitSchema = mongoose.Schema({

  name: {type: String, require: true, trim: true, unique: true},

  color: {type: String, require: true},

  quantity: Number,

  ripe: Boolean

});

Here a few extra properties are set for the schema's name field. It's now a required field that will be trimmed for any extra whitespace. Additionally, the name values must all be unique.

Creating a Model

Next, use this schema to define a model:

// define the model

var Fruit = mongoose.model('fruit', fruitSchema);

Here the model is created using the fruitSchema that was defined earlier. The first argument, ‘fruit', sets the name for the model. This value corresponds to the name that will be used to save the collection, in this case fruits.

Pay careful attention to the API here: In mongoose.Schema Schema is capitalized, whereas in mongoose.model model isn't capitalized.

After creating the structure, create a new instance of the model:

// create a new instance of the model

var apple = new Fruit({

  name: 'apple',

  color: 'red',

  quantity: 3,

  ripe: true

});

This snippet creates a new fruit along the schema that was defined earlier.

Saving the Model

Simply creating the model in Mongoose isn't enough—you still have to save it to MongoDB. To do so, use the save() method:

// save the model

apple.save(function (err, apple) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(apple);

  }

});

This saves the model as a document in MongoDB. Anytime you create or modify the data in the model, simply use the save() method to sync those changes to the database.

Putting all the preceding code together:

// include the mongoose module

var mongoose = require('mongoose'),

// connect to a MongoDB database

mongoose.connect('localhost', 'mydb'),

// connection

var db = mongoose.connection;

db.on('error', console.error.bind(console, 'Connection error:'));

db.once('open', function callback () {

  // define the schema

  var fruitSchema = mongoose.Schema({

    name: String,

    color: String,

    quantity: Number,

    ripe: Boolean

  });

  

  // define the model

  var Fruit = mongoose.model('fruit', fruitSchema);

  

  // create a new instance of the model

  var apple = new Fruit({

    name: 'apple',

    color: 'red',

    quantity: 3,

    ripe: true

  });

  // save the model

  apple.save( function(err, apple) {

    if (err) {

      console.log(err);

    }

    else {

      console.log(apple);

    }

  });

});

Just to recap what's going on here:

1. The script starts by including the Mongoose module.

2. It then creates a connection to the database with error and success callbacks.

3. In the open callback, the script defines a schema.

4. It uses the schema to define a model and creates a new instance of that model.

5. The model is saved as a MongoDB collection.

Reading Data

Reading data from a Mongoose collection is easy. But first add some more data to the collection so you have something to work with:

var orange = new Fruit({

  name: 'orange',

  color: 'orange',

  quantity: 5,

  ripe: true

});

var banana = new Fruit({

  name: 'banana',

  color: 'green',

  quantity: 1,

  ripe: false

});

orange.save( function(err, orange) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(orange);

  }

});

banana.save( function(err, banana) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(banana);

  }

});

Finding All Models

To read the data that has been saved to a collection, use the find() method on the corresponding model:

// define the model

var Fruit = mongoose.model('fruit', fruitSchema);

// select all the fruit

Fruit.find( function(err, fruit) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(fruit);

  }

});

This code selects all the models in the collection, as shown in this output:

[ { name: 'apple',

    color: 'red',

    quantity: 3,

    ripe: true,

    _id: 50dcd5b8e890ee50000000001,

    __v: 0 },

  { name: 'orange',

    color: 'orange',

    quantity: 5,

    ripe: true,

    _id: 50dcd5b8e890ee0000000001,

    __v: 0 },

  { name: 'banana',

    color: 'green',

    quantity: 1,

    ripe: false,

    _id: 50dcd5b8e890ee0000000002,

    __v: 0 } ]

Finding Specific Models

You can also narrow down the models you select by passing a first argument to the find() method:

// select just the orange

Fruit.find({name: 'orange'}, function(err, fruit) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(fruit);

  }

});

This snippet selects only those models with a name value of ‘orange', as shown in this output:

[ { name: 'orange',

    color: 'orange',

    quantity: 5,

    ripe: true,

    _id: 50dcd5b8e890ee0000000001,

    __v: 0 } ]

Mongoose supports all of MongoDB's robust querying options. For example, you can select models using a regular expression:

// select fruits that end in 'e'

Fruit.find({name: /e$/}, function(err, fruit) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(fruit);

  }

});

This example selects fruits that end in the letter ‘e', using the regex /e$/, as shown here:

[ { name: 'apple',

    color: 'red',

    quantity: 3,

    ripe: true,

    _id: 50dcd5b8e890ee50000000001,

    __v: 0 },

  { name: 'orange',

    color: 'orange',

    quantity: 5,

    ripe: true,

    _id: 50dcd5b8e890ee0000000001,

    __v: 0 } ]

You can also use MongoDB's operators, for example:

// select quantities less than 4

Fruit.find({quantity: {$lt: 4}}, function(err, fruit) {

  if (err) {

    console.log(err);

  }

  else {

    console.log(fruit);

  }

});

This snippet selects fruits with a quantity less than 4, as you can see from this output:

[ { name: 'apple',

    color: 'red',

    quantity: 3,

    ripe: true,

    _id: 50dcd5b8e890ee50000000001,

    __v: 0 },

  { name: 'banana',

    color: 'green',

    quantity: 1,

    ripe: false,

    _id: 50dcd5b8e890ee0000000002,

    __v: 0 } ]

Accessing Fields from a Model

Once you've selected a model from the collection, drilling down into the individual fields is simple. You may have noticed that the output of the previous examples returns JSON objects. You can use the keys from these objects to get at whatever field data you need. For example:

// select all fruits

Fruit.find(function(err, fruits) {

  // loop through the results

  fruits.forEach(function(fruit) {

    // log the fruit's name

    console.log( fruit.name );

  }

});

This script loops through the results of the query, outputting the name of each fruit, like so:

apple

orange

banana

Using this, you can create any kind of output you need, for example:

// loop through the results

fruits.forEach(function(fruit) {

  // log info about the fruit

  console.log( 'I have ' + fruit.quantity + ' '

    + fruit.color + ' ' + fruit.name

    + ( fruit.quantity != 1 ? 's' : '' ) );

}

This script prints a more readable output:

I have 3 red apples

I have 5 orange oranges

I have 1 green banana

Other Database Options

If you're using Node, chances are that you'll also want to use MongoDB. But that said, MongoDB isn't for everything, and there are times when it's better to work with a relational database like MySQL. Fortunately, there's a MySQL module you can use with Node, which you can read about here: https://github.com/felixge/node-mysql.

Additionally, besides MongoDB, another popular NoSQL database for Node is Redis. Redis represents everything as key-value pairs and is ideal for really simple data that is updated frequently. To learn more about Redis, visit: https://github.com/mranney/node_redis.

Summary

In this chapter, you discovered how to create a lightning-fast, super-scalable database to match your Node deployment. You found out how to install the NoSQL database MongoDB and how to use the native MongoDB driver for Node. With that driver, you used CRUD techniques that would even make relational databases jealous. Next, you learned about the object modeling tool, Mongoose, which allows you to save data in models and then sync those models to a MongoDB. Finally, you were introduced to some MongoDB alternatives, such as the MySQL module for Node, as well as the NoSQL database Redis. In the next chapter, you combine your Node and MongoDB skills with WebSockets to build a real-time app.

Additional Resources

Documentation

MongoDB Documentation: http://docs.mongodb.org/manual

MongoDB Native NodeJS Driver Documentation: https://github.com/mongodb/node-mongodb-native

Mongoose Documentation: http://mongoosejs.com/docs/guide.html

GUI Tools

MongoHub (Mac OS X): http://mongohub.todayclose.com

UMongo (Linux, Windows & Mac): http://edgytech.com/umongo

Other Tools: http://www.mongodb.org/display/DOCS/Admin+UIs

Books

MongoDB: The Definitive Guide by Kristina Chodorow, published by O'Reilly Media, Inc. (2010): http://bit.ly/mongodb-definitive-guide

MongoDB In Action by Kyle Banker, published by Manning Publications (2011): http://bit.ly/mongodb-in-action-book

General NoSQL Info

NoSQL Databases: http://nosql-database.org

NoSQL Distilled (Book): http://bit.ly/nosql-distilled

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset