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.
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.
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.
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.
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