- Web Development with MongoDB and Node.js
- Jason Krol
- 634字
- 2021-08-05 17:51:04
Writing your first app
Now that you have everything installed and confirmed that it's all working, you can write your first quick app that will use both Node and MongoDB. This will prove that your environment is good to go, and you're ready to get started. In addition, it will give you a brief taste of the world of Node and MongoDB development! Don't worry if a lot of the following is confusing or just doesn't make sense to you—it will all be made clear throughout the rest of the book!
Step one is to create a folder that you can work from while creating files and installing Node modules. From your home or development folder, execute the following commands:
$ mkdir testapp $ cd testapp
The code
The first thing you need to do before you write any code is download any modules you plan to use with your app from npm. Since this is a basic app, you'll only need to use the MongoDB Node driver. You can easily install this by executing the following command:
(term_1)$ npm install mongodb
After npm installs the MongoDB driver, you can list the contents of the directory, and you'll see that a new folder named node_modules
was created. This is where, surprisingly enough, all node modules are stored whenever you install them from npm. Inside the node_modules
folder should be a single folder named mongodb
.
Note
For the purposes of this demo, it's going to be a little easier if you have three separate terminal windows open. I've labeled each with (term_N)
to make things a little more clear as we go.
Now let's write a simple app to test things out. This app is going to basically connect to our locally running MongoDB server, insert a few records as seed data, and then output those same records to the screen. The code should give you some insight into the use of callbacks and the potential pitfall of Node's async nature.
You can download a gist of the following code at http://bit.ly/1nvTVcM.
Using your editor of choice, create a new file named app.js
, save it to the same location you executed npm install
, and insert the following complete set of code:
var MongoClient = require('mongodb').MongoClient;
First, we require
the MongoDB Node driver that you installed via npm. require
is a Node.js convention to bring in external dependencies—similar to using
or import
in other languages:
var dbhost = 'mongodb://localhost:27017/test', myCollection = 'chapter2';
Next we declare a dbhost
variable for the database server information and collection (table) you want to work with. Here, test
is the database you want to use and chapter2
is the collection. In MongoDB, if you reference and try to use a collection that doesn't exist, it will automatically be created.
The seedData
function will first check to see whether we already have any records in our collection or not. If the collection is empty, a few sample records will be inserted. Note that the parameters for this function are the database and a callback function. The callback function will be called once the work is finished:
var seedData = function(db, callback) { db.collection(myCollection).find({}, {}, {}) .toArray( function(err, docs) { if (docs.length <= 0) { console.log('No data. Seeding...'); // count each record as its inserted var ihandler = function(err, recs) { if (err) throw err; inserted++; } var toinsert = 2, inserted = 0; // perform a MongoDB insert for each record db.collection(myCollection).insert({ 'Title': 'Snow Crash', 'Author': 'Neal Stephenson' }, ihandler); db.collection(myCollection).insert({ 'Title': 'Neuromancer', 'Author': 'William Gibson' }, ihandler); // wait for the 2 records above to be finished // inserting var sync = setInterval(function(){ if(inserted === toinsert) { clearInterval(sync); callback(db); } }, 50); return; } callback(db); return; } ); }
Take note of the use of setInterval
. This is used because Node by its very nature is asynchronous, which means it will execute all of the code line by line and won't stop and wait for anything to finish. Since our callback might get called before we finish inserting our records (inserts to the MongoDB server might take longer than our lines of code can execute). We will implement a simple count mechanism that will count the number of records inserted and compare it to the number of records expected to be inserted. This will occur in a loop every 50 milliseconds. Once the fifth and final record has been inserted, our callback will then be called with the database object passed into it as a parameter.
Note
Using setInterval
like this is actually a bad practice. Normally, we would rely on a third-party module or framework to handle a situation like this to prevent the need for intervals as well as improve readability. I only included it for the sake of brevity.
The showDocs
function will basically connect to the database using the same collection name we defined earlier, and loop through every record returned and output the information to the screen using a basic console.log()
:
var showDocs = function(db) { console.log("Listing books:"); var options = { sort: [['Title',1]] }; // find and return an array of all records in the collection db.collection(myCollection).find({}, {}, options) .toArray( function(err, docs) { if (err) throw err; // for each item in the collection, print the title and author for(var d = 0; d < docs.length; d++) { console.log(docs[d].Title + '; ' + docs[d].Author); } db.close(); } ); }
Finally, we will use the actual MongoClient
that we required in the very first line of the app and use its connect()
method. The callback that is executed once the connection is established is defined right inline using an anonymous function. This function calls seedData
and passes it the db
object as well as the callback we want to use; in this case, our showDocs
function:
MongoClient.connect(dbhost, function(err, db){ if (err) throw err; // once connected, execute the seedData function to start the app seedData(db, showDocs); });
Ironically, even though the MongoClient.connect()
code is declared at the bottom of the file, it's actually the first set of code to execute. In the next chapter, you will learn how to write your own modules that you can require so that the seedData
and showDocs
functions exist in separate files.
Launch the sample app
Once you have the complete code saved to app.js
, it's time to execute it and see what happens. However, before you can launch an app that clearly relies on a connection to MongoDB, you need to first boot up a server:
(term_2)$ mongod
Note
In Windows, if you haven't set a PATH variable for mongod
, you may need to use the full path while executing MongoDB, which is c:\mongodb\bin\mongod.exe
. For your needs, the remainder of this book will refer to the mongod
command, but you may always need to execute the full path in each instance.
Now to launch the app itself, execute the following command:
(term_1)$ node app.js
When the app first executes, you should see the following output:
No data. Seeding... Listing books: Neuromancer; William Gibson Snow Crash; Neal Stephenson
If you were to run the app again, you will see that the No data. Seeding...
message doesn't appear. This is because our app is smart enough to check to make sure it doesn't need to insert the records every time it runs (only whenever there is no data in the collection).
Check the actual database
Let's take a quick look at the database itself to see what happened during the execution of the app. Since the server is currently up and running, we can connect to it using the mongo shell—a command line interface to the MongoDB server. Execute the following commands to connect to the server using mongo
, and run a query against the chapter2
collection:
(term_3)$ mongo MongoDB shell version: 2.4.8 connecting to: test > show collections chapter2 system.indexes > db.chapter2.find().pretty()
You should see something similar to the following output that lists each of the records that were inserted during the seedData
function of the app:
{ "Title" : "Snow Crash", "Author" : "Neal Stephenson", "_id" : ObjectId("5326268a4937f98403fca895") } { "Title" : "Neuromancer", "Author" : "William Gibson", "_id" : ObjectId("5326268a4937f98403fca896") }
Note that the use of .pretty()
is simply a mongo shell command that properly formats the output of any queries you execute. Without it, the preceding output would have been displayed as a single line and would have been fairly unreadable.