Chapter 7. Persisting Data with MongoDB

With almost any application written for the Web nowadays, a highly interactive application is of limited value if the interactions of its users aren't permanently saved. The most common way to handle this requirement is with a database that permanently saves data to the filesystem. Imagine a world where all of the data for your application (registered users, order transactions, and social interactions) were all stored within the temporary memory of the server the application is running on. The moment that server is turned off or rebooted, all of your application that would be lost. Relying on a database to store this data permanently is crucial to the success of any dynamic application.

In this chapter, the following topics will be covered:

  • Connecting to MongoDB
  • An introduction to Mongoose
  • Schemas and models
  • Adding CRUD to our controllers

In the previous chapter, we wrote and accounted for the actual logic of our application. The next step in building our application is to connect it to a database so that our users' interactions and data can be permanently saved and retrieved. Without connecting our application to a database server to persist data, every interaction by a visitor will be lost the second they left the page. Without some kind of database server to store our data, most of the websites we interact with on a daily basis wouldn't even exist. Technically, we can get around this by storing data in memory, but the moment our web server restarts or crashes, all of that data would be lost.

Here is a general breakdown of how our data is going to be persisted for every visitor interaction in our app:

Persisting Data with MongoDB

Consider the previous diagram, which reflects the typical lifecycle of a web application request:

  1. A visitor submits a request to view a page on our application via their web browser.
  2. Our Node.js server receives this request and queries a MongoDB server for any data.
  3. Our MongoDB server returns the queried data back to our Node.js server.
  4. Our Node.js server takes that data and builds it into the view model and then sends the rendered HTML page back to the browser.
  5. The web browser receives the response from our Node.js server and renders the HTML.
  6. This cycle repeats typically for every interaction by every visitor.

For the purposes of this book, we are using MongoDB as our primary data store—but the reality is that we can use anything to store data: mySQL, postgreSQL, MS SQL, the filesystem, and so on.

Using MongoDB with Node

Before we officially implement MongoDB into our actual application, let's first take a look at some basic examples of connecting to a MongoDB server from within Node.js.

Create a new project folder to store some sample code to experiment with. I'll call my folder mongotest. Inside this folder, create a new file called test.js and in this file we will play around with some code to test how to connect to MongoDB and how to insert and retrieve some data. The first thing we need to do in order to connect to a MongoDB server from node is to require a mongodb module.

To get started, change directories into the new mongotest folder and install the mongodb module using npm:

$ cd mongotest
$ npm install mongodb

Note

Don't be confused by the module's name. The mongodb npm module isn't MongoDB itself, but rather a third-party npm module that facilitates communicating to a MongoDB server from within Node.js. Also, because this is just a sample project to experiment with, we don't require the --save flag with npm install since we aren't maintaining a package.json file.

Connecting to MongoDB

Now that the mongodb module is installed, we can use it in our experimentation file. Boot up your editor, and create a file named test.js. Insert the following block of code into it:

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

MongoClient.connect('mongodb://localhost:27017/mongotest', function(err, db) {
    console.log('Connected to MongoDB!'),

    db.close();
});

Executing the preceding code should log Connected to MongoDB! to your screen.

The first thing you'll notice is that we require the mongodb module, but we specifically use the MongoClient component of the module. This component is the actual interface we use to actively open a connection to a MongoDB server. Using MongoClient, we pass the mongodb://localhost:27017/mongotest string URL to our local server as the first parameter. Notice that the path in the URL points to the server and then the name of the database itself.

Note

Remember to make sure you have your local MongoDB server instance running in another terminal for the duration of this chapter. To do so, open a command-line terminal window and execute $ mongod. Your server should launch and log information to the screen ending with [initandlisten] waiting for connections on port 27017.

You may find that when run your application, you receive a stack trace error with something like the following code:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: failed to connect to [localhost:27017]

If this happens, you should recognize that it failed to connect to localhost on port 27017—also known as the port that our local mongod server runs under by default.

Once we have an active connection to our database server, it's as if we are running the mongo shell command. The MongoClient callback function returns a database connection object (that we named db in our code, but could have been named anything), which is almost exactly the same object we work with in the mongo shell when we execute use databasename. Knowing this, at this point, we can use the db object to do anything we can do via the mongo shell. The syntax is slightly different, but the idea is generally the same.

Inserting a document

Let's test out our new db object by inserting a record into a collection:

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

MongoClient.connect('mongodb://localhost:27017/mongotest', function(err, db) {
    console.log('Connected to MongoDB!'),

    // using the db connection object, save the collection 'testing' to 
    // a separate variable:
    var collection = db.collection('testing'),
    // isert a new item using the collection's insert function:
    collection.insert({'title': 'Snowcrash'}, function(err, docs) {
        // on successful insertion, log to the screen the new
        // collection's details:
        console.log(docs.length + ' record inserted.'),
        console.log(docs[0].title + ' – ' + docs[0]._id);
        // finally close the connection:
        db.close();
    });
});

In the preceding code, we establish a connection to the database and execute a callback once the connection is complete. That callback receives two parameters, the second of which is the db object itself. Using the db object, we can get a collection we want to work with. In this case, we save that collection as a variable so that we can more easily work with it throughout the rest of our code. Using the collection variable, we execute a simple insert command and pass in the JSON object we want to insert into the database as the first parameter.

The callback function that executes after insert accepts two parameters, the second of which is an array of documents affected by the command; in this case, an array of documents that we inserted. Once insert is complete and we are inside the callback function, we log some data. You can see that the length of the docs array is 1 as we only inserted a single document. Furthermore, you can see that the single document in the array is the document we inserted, although now it has an extra _id field since MongoDB handles that automatically.

Retrieving a document

Let's prove our code a little bit more by adding a findOne call to look up the document we just inserted. Change the code in test.js to match the following example:

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

MongoClient.connect('mongodb://localhost:27017/mongotest', function(err, db) {
    console.log('Connected to MongoDB!'),

    var collection = db.collection('testing'),
    collection.insert({'title': 'Snowcrash'}, function(err, docs) {
        console.log(docs.length + ' record inserted.'),
        console.log(docs[0]._id + ' - ' + docs[0].title);

        collection.findOne({title: 'Snowcrash'}, function(err, doc) {
            console.log(doc._id + ' - ' + doc.title);
            db.close();
        });
    });
});

In this code, we are inserting a record in exactly the same way as before; only this time, we are performing findOne on title. The findOne function accepts a JSON object to match against (this can be as precise or loose as you want) as its first parameter. The callback function that executes after findOne will contain the single document that was found as its second parameter. If we executed a find operation, we would have received an array of matching documents based on the search criteria.

The output of the last mentioned code should be:

$ node test.js
Connected to MongoDB!
1 record inserted.
538bc3c1a39448868f7013b4 - Snowcrash
538bc3c1a39448868f7013b4 – Snowcrash

In your output, you might notice that the _id parameter being reported on insert doesn't match the one from findOne. This is likely the result of running the code multiple times, which results in multiple records with the same title being inserted. The findOne function will return the first document found in no particular order, so chances are the document returned may not be the last one inserted.

Now that you have a basic understanding of how to easily connect and communicate with a MongoDB server from Node, let's take a look at how we can work with MongoDB in a way that's a little less raw.

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

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