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:
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:
Consider the previous diagram, which reflects the typical lifecycle of a web application request:
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.
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
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.
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.
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.
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.
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.
3.142.250.203