In unit 2, you built web applications with Express.js. Structuring your applications to use the model-view-controller (MVC) architecture, you can now handle requests through your controllers and serve views. The third essential piece is models, with which you’ll organize data that you plan to store permanently. In this lesson, you install MongoDB, the database system that you’ll use to store persistent data. You also explore what makes document database structure in MongoDB particularly convenient for Node.js applications. By the end of the lesson, you’ll have a database set up and connected to your application.
This lesson covers
You want to start saving data from your application into a database, but you’re unsure which database to use. With Node.js, you can work with practically any common database, such as MySQL, PostgreSQL, Cassandra, Redis, and Neo4j. You can get a sense of the most supported and popular database management systems by exploring their associated packages on npm.
MongoDB, however, offers a unique style of data storage that resembles JSON—a JavaScript-friendly format that may make working with databases easier for you as you delve into saving data with Node.js for the first time.
Storing data is arguably the most important part of application development. Without long-term storage, you’re limited in the way you can interact with your users. The data in every application you’ve built to this point disappeared each time you restarted the application. If data from a social network were to disappear every time a user closed his browser or every time you restarted that application, users would have to create new accounts and start from scratch.
A database is an organization of your data designed for easy access and efficient changes made by your application. A database is like a warehouse: the more items you need to store, the happier you’ll be with an organized system that helps you find those items. Like a web server, your application connects to a MongoDB database and requests data.
Throughout this unit, I discuss how to save information to a database for long-term storage. Your data will persist, even if the application is shut down.
MongoDB is an open-source database program that organizes data by using documents. MongoDB documents store data in a JSON-like structure, allowing you to use key-value pairing to associate data objects with properties.
This system of storage follows a familiar JavaScript syntax. Notice in figure 13.1 that a document’s contents resemble JSON. In fact, MongoDB stores documents as BSON (a binary form of JSON). Unlike relational databases used by the majority of applications, MongoDB’s nonrelational database system leads the Node.js application community.
This book focuses on MongoDB and on how its documents complement a JavaScript-based application platform like Node.js. It’s worth noting what MongoDB is not, however, as well as how the rest of the programming world is working with databases.
Most databases used by software and web applications use a different model of data storage from the document structure used in MongoDB. Most databases are relational, meaning that they associate data via tables, like a standard spreadsheet. Within these tables, columns define the type of data that should be stored, and rows store the values that correspond to the columns. In the following figure, data representing people, courses, and which people are enrolled in certain courses is displayed in separate tables.
Example relational database structure
In this example, two tables are associated by their ID values. To connect a person with their desired cooking course, the IDs of the items from the people and courses tables are added to new rows in a join table. The join table generally holds only IDs of associated items to define a relationship among those items. This relationship designed through reference IDs is where the database system gets its name. Databases that use this structure are often SQL-based, making MongoDB a NoSQL database system.
You could set up a relational database with Node.js—in fact, many applications do—but to best make use of a SQL database, it helps to know how to write in the SQL language. The MongoDB query language is simpler to understand for people who have a Java-Script background.
For more information on relational databases, I recommend reading the overview by Oracle at https://docs.oracle.com/javase/tutorial/jdbc/overview/database.html.
In this section, you install MongoDB and look at some data. The installation process is a bit different for Windows and Macintosh. For the Mac, the recommended approach is a terminal command-line tool called Homebrew. You can install Homebrew by entering the command shown in the next listing.
mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew 1
Homebrew is a tool that helps you install software and other low-level tools such as database management systems. For more information, visit https://brew.sh.
When Homebrew is installed, you should be able to enter brew in any new terminal window and see a list of available Homebrew commands, one of which is brew install. Install MongoDB by running brew install mongodb.
If your computer throws an error or complains about permissions issues at any point in the installation, you may need to run the command as a superuser by appending sudo to the command. Then you’ll be prompted to enter your computer’s login password.
Next, create a folder called db within another folder called data at your computer’s root level (as far back as you can cd .. in a terminal window). You can create this folder by entering mkdir -p /data/db in a terminal window.
You may need to give permissions to your user account to use this folder. To do so, run sudo chown <your_username> /data/db, and enter your computer’s password. For Windows, the steps are as follows:
In Windows, you may need to add the MongoDB folder path to your environment’s PATH variable. To add it, right-click Computer, choose Properties Advanced system settings Environment variables Edit environment variables PATH, and add your MongoDB executable path to this string. Your MongoDB path might look something like C:Program FilesMongoDBServer3.6.2inmongod.exe.
For more installation instructions, including those for Ubuntu Linux machines, go to https://docs.mongodb.com/v3.0/tutorial/install-mongodb-on-ubuntu.
So far, you’ve gotten MongoDB installed on your computer. Like a web server, Mongo-DB needs to be started to create new databases for your applications. You can start MongoDB by running mongod in a terminal window. This command assigns MongoDB a port and establishes the location of its databases at data/db.
To start and stop MongoDB with Homebrew on a Mac, run brew services start mongodb or brew services stop mongodb. Homebrew runs the database server in the background, so if mongod doesn’t work, you may have started MongoDB with Homebrew elsewhere.
You can test whether Mongo was installed successfully by typing mongo in a new terminal window. This command brings up the MongoDB shell, an environment within which you can run MongoDB commands and view data. This shell environment is similar to REPL because it isolates your terminal window to allow you to interact purely with MongoDB syntax. When you have some data to work with, you can further explore this environment.
Now that MongoDB is running, it’s ready to receive commands to add, view, delete, or otherwise change data. Before you connect MongoDB to your application, you can test some commands in the MongoDB shell.
Commands that you run in the MongoDB shell are permanent. If you delete data (or an entire database), there’s no going back.
Run mongo in a new terminal window. This command should prompt the shell to start. You’ll be greeted by your MongoDB version number, potentially a few warnings (which you can ignore for now), and the familiar > to indicate that the shell is active and ready for commands.
MongoDB can store multiple databases; it’s a management system for all your applications’ databases. To start, the MongoDB shell places you in the test database. You can see this test database by entering db, to list your current database, after the prompt (figure 13.2).
To view all available databases, run show dbs. With a clean install of MongoDB, your shell’s response should look like the next listing. Your test database is one of three that comes prepackaged with MongoDB. To the right of the database name is the size of the database. Because you haven’t stored any data yet, the databases are understandably empty.
admin 0.000GB local 0.000GB test 0.000GB 1
You can create a new database and simultaneously switch into it by entering use <new_database_name>. Try switching to a new database for the recipe application by entering use recipe_db. Then run db again to see that you’re within the recipe_db database.
You won’t see your new database in the list of databases until data is added.
To add data to your database, you need to specify a collection name with which that data is associated. A MongoDB collection is representative of your data model, storing all documents related to that model within the same grouping. If you want to create a contact list for the recipe application, for example, create a new collection and add a data item with the command shown in the following listing. The insert method runs on a MongoDB collection to add elements of a JavaScript object to a new document.
db.contacts.insert({ name: "Jon Wexler", email: "[email protected]", note: "Decent guy." }) 1
At this point, there’s no strict collection structure; you can add any values to new documents without needing to follow previous data patterns. Insert another item into the contacts collection with these properties: {first_name: “Jon”, favoriteSeason: “spring”, countries_visited: 42}. MongoDB lets you add these seemingly conflicting data elements.
Just because MongoDB lets you store inconsistent data doesn’t mean that you should. In lesson 14, I discuss ways of organizing data around your application’s models.
To list the collection’s contents, you can enter db.conntacts.find(). You should see a response that looks like the next listing. Both inserted items are present, with an extra property added by MongoDB. The id property stores a unique value that you can use to differentiate and locate specific items in your database.
{"_id": ObjectId("5941fce5cda203f026856a5d"), "name": "Jon Wexler", "email": "[email protected]", "note": "Nice guy."} 1 {"_id": ObjectId("5941fe7acda203f026856a5e"), "first_name": "Jon", "favoriteSeason": "spring", "countries_visited": 42}
To keep your data organized and unique, MongoDB uses an ObjectId class to record some meaningful information about its database documents. ObjectId("5941fe7acda203f026856a5e"), for example, constructs a new ObjectId representing a document in your database. The hexadecimal value passed into the ObjectId constructor references the document, a timestamp of the record’s creation, and some information about your database system.
The resulting ObjectId instance provides many useful methods that you can use to sort and organize data in your database. As a result, the _id property becomes a more useful feature in MongoDB than a string representation of the document ID.
Try searching for a specific item in the contacts collection by entering db.contacts .find({_id: ObjectId("5941fce5cda203f026856a5d")}).
Replace the ObjectId in this example with one from your own database results.
As you become familiar with MongoDB, you may want a more user-friendly window into your MongoDB databases than the MongoDB shell in terminal. The people at MongoDB agreed and have produced a MongoDB graphical user interface called MongoDB Compass for all major operating systems.
MongoDB Compass is straightforward to use. To view the database that you set up for your recipe application, follow these steps:
I recommend using MongoDB Compass as a supplemental tool while you work with MongoDB in your application.
You can use many MongoDB commands. Table 13.1 lists a few that you should know about.
Command |
Description |
---|---|
show collections | Displays all the collections in your database. Later, these collections should match your models. |
db.contacts.findOne | Returns a single item from your database at random or a single item matching the criteria passed in as a parameter, which could look like findOne({name: ‘Jon’}). |
db.contacts.update({name: “Jon”}, {name: “Jon Wexler”}) | Updates any matching documents with the second parameter’s property values. |
db.contacts.delete({name: “Jon Wexler”}) | Removes any matching documents in the collection. |
db.contacts.deleteMany({}) | Removes all the documents in that collection. These commands can’t be undone. |
For more practice, view the command cheat sheet at https://docs.mongodb.com/manual/reference/mongo-shell/.
In the next section, you see how to add MongoDB to your Node.js application.
show collections lists the collections within the active database in your MongoDB shell.
To add MongoDB to your Node.js recipe application, enter your project folder (or create a newly initialized project) in terminal, and install the mongodb package by running npm i mongodb -S. This command saves the mongodb package to your project’s package.json dependencies.
In the corresponding code repository for this lesson, some views and styling rules have been added from the last capstone project.
At the top of your main.js file, add the code shown in listing 13.5. Require the MongoDB module to use the MongoClient class. MongoClient sets up a connection to your local database at its default port. The callback function returns your connection to the MongoDB server. Then get the database called recipe_db from your connection to the server. If there’s no database by the name provided, MongoDB creates one for use in the app.
Remember to run mongod to ensure that your MongoDB server is running before you try to connect to it.
Next, ask the database to find all records in the contacts collection and return them in an array. The resulting data is returned in the callback function. Then you can log the results to the console.
const MongoDB = require("mongodb").MongoClient, 1 dbURL = "mongodb://localhost:27017", dbName = "recipe_db"; MongoDB.connect(dbURL, (error, client) => { 2 if (error) throw error; let db = client.db(dbName); 3 db.collection("contacts") .find() .toArray((error, data) => { 4 if (error) throw error; console.log(data); 5 }); });
The find query method here works differently from a find query in a traditional functional programming language. If you get no match when you use find in MongoDB, you get an empty array.
You can use the same commands within your Node.js application that you did in the MongoDB shell. To add a new item to the database, for example, you can add the code in listing 13.6 within your MongoDB connection callback function.
As when you query all the items in the database, you connect to the contacts collection and insert an item. If the new data was inserted successfully, you log that database message to the console.
db.collection("contacts") .insert({ name: "Freddie Mercury", email: "[email protected]" }, (error, db) => { 1 if (error) throw error; console.log(db); 2 });
In lesson 14, you explore a package called Mongoose, which works with MongoDB to provide a bit more organization to your application’s storage.
True or false: If you try to connect to a database that doesn’t exist, MongoDB throws an error.
False. MongoDB creates a new database by the name you provided instead of throwing an error.
In this lesson, you learned how to set up MongoDB and how to use certain commands to manage databases on your computer. At the end of the lesson, you inserted collections and documents into your own database and connected that database to your Node.js application. In lesson 14, you build models to represent the types of data that you want to store in your application.
Imagine that you’re creating an application to track ice-cream-truck statistics. Create an appropriately named database with a collection called ice_cream_flavors. Try inserting some flavors and include fields that would help with your statistics analysis.