{ The Rithm Blog. }

MongoDB is Easy December 06, 2018

MongoDB is a popular NoSQL database provider. Here at Rithm School we used to teach MongoDB in conjunction with Node.js. Recently, however, we have switched our Node.js curriculum to utilize PostgreSQL. For a taste of what that looks like, check out Joel's blog post or our free online curriculum on relational databases with Node/Express.

Much of the reason for this curriculum change is that relational databases, the SQL language, and ORMs can take a long time to master and are more widely-used across the industry. We decided therefore it would be best if our students could focus on mastering SQL and relational databases (the dominant database tech for the last 40 years) rather than split that time between a completely different technology that has only recently risen in popularity.

But another significant reason that I would like to argue is: MongoDB really isn't that hard to learn and master! If you're comfortable with JavaScript, JSON, and Node.js/Express.js (which all of our graduates are), then teaching yourself MongoDB can be a cakewalk. Especially if you have this blog post! 😉

MongoDB

The Basics of MongoDB

MongoDB is a document store database management system that stores JSON documents in collections and queries them with JavaScript.

Technically, they are stored in a binary-JSON format called BSON, but for our purposes the documents all look and behave like JSON. ...If it quacks like a duck... 🦆

A document is just a JSON object, for example:

{
  "firstName": "Whiskey",
  "lastName": "Lane",
  "species": "dog",
  "hobbies": ["sleeping", "eating"],
  "age": 4
}

A collection is just a group of (hopefully) similar-looking documents. The above document could live inside of a pets collection.

A database in MongoDB is just a set of collections, for our purposes we can think of there being one database per app.

No Schemas

MongoDB does not impose schemas onto any of the data; it is considered a schemaless database system. It's up to the application / developer to enforce what documents are supposed to look like.

To demonstrate, I could be evil and insert the following document into our pets collection:

{
  "product": "Nintendo Switch",
  "price": 299
}

...and MongoDB would not yell at me at all 🙈, even though that's definitely not a pet.

Thus, you've got to be careful what you're putting into your collections. The flexibility can be enjoyable (no migrations!) but the lack of structured data is a big price to pay (some would argue, too great of a price).

"Webscale"

There's a whole lot of NoSQL and MongoDB marketing and evangelism around high scalability, distributed systems, and a complicated concept called sharding, but we will leave such discussions to the dev-ops professionals for the time being!

Though, I should point out that a common criticism of companies widely adopting MongoDB is focusing too much on theoretical scalability at the expense of a better / more appropriate data model. But we at Rithm will withold judgement for now. 😅

Installing MongoDB on OSX

The hardest part of learning MongoDB is going to be installing it. But I'll try to make it as easy as possible for you!

Installation Process

  1. Use homebrew.

  2. Run this command in your terminal to install MongoDB through homebrew: brew install mongodb

  3. Run the following commands in your terminal:

sudo mkdir -p /data/db
sudo chmod 0755 /data/db && sudo chown $USER /data/db

These commands are just creating a data folder for MongoDB files and then setting the appropriate permissions.

Using MongoDB

  1. In one terminal tab, run the command mongod. This ~summons the dark lord MON GOD~ runs the database server program. You can't use this terminal tab while mongod is running in it. MongoD stands for Mongo Daemon, a process that needs to run in the background so you can query and stuff.

  2. In another terminal, run the command mongo. This opens up the MongoDB Interactive Shell program that lets you execute queries in JavaScript from the command line. To quit the shell, the command is exit.

The MongoDB Shell

Make a Database, a Collection, and Documents

With mongod running, enter the MongoDB shell with the mongo command.

We can create and connect to a new database on the fly just by using it. In the shell type use pets_db. If you ever want to list all your databases, type show dbs.

Now that we're connected to pets_db, let's create a collection. How do you create a collection? Just insert a document into it, and it magically becomes a thing, just like using a database also creates it magically.

Let's insert the Whiskey document from above:

db.pets.insert({
  firstName: 'Whiskey',
  lastName: 'Lane',
  species: 'dog',
  hobbies: ['sleeping', 'eating'],
  age: 4
});

Let's insert two more documents at once with the insertMany query. This function accepts an array of documents.

db.pets.insertMany([
  {
    firstName: 'Gandalf',
    species: 'owl',
    age: 1
  },
  {
    firstName: 'Socrates',
    species: 'cat'
  }
]);

Notice that these pet documents don't have as many fields as Whiskey. But that's okay, because there isn't any schema or anything that we need to abide by!

Querying

Let's query the list of all the pets:

Shell Command

db.pets.find();

Result

{ "_id" : ObjectId("5c08c8c8abcff34df52dded2"), "firstName" : "Whiskey", "lastName" : "Lane", "species" : "dog", "hobbies" : [ "sleeping", "eating" ], "age" : 4 }
{ "_id" : ObjectId("5c08c8cfabcff34df52dded3"), "firstName" : "Gandalf", "species" : "owl", "age" : 1 }
{ "_id" : ObjectId("5c08c8cfabcff34df52dded4"), "firstName" : "Socrates", "species" : "cat" }

Hmm that's alright but the results are all bunched up. Let's make it more readable:

Shell Command

db.pets.find().pretty();

Result

{
  "_id" : ObjectId("5c08c8c8abcff34df52dded2"),
  "firstName" : "Whiskey",
  "lastName" : "Lane",
  "species" : "dog",
  "hobbies" : [
    "sleeping",
    "eating"
  ],
  "age" : 4
}
{
  "_id" : ObjectId("5c08c8cfabcff34df52dded3"),
  "firstName" : "Gandalf",
  "species" : "owl",
  "age" : 1
}
{
  "_id" : ObjectId("5c08c8cfabcff34df52dded4"),
  "firstName" : "Socrates",
  "species" : "cat"
}

That looks nicer!

Note the _id field, a primary key that was inserted by MongoDB for us on each of the documents. This is MongoDB's way of keeping track of things, but we can also query by it if necessary.

Let's query for Whiskey and only get the first result back. Also, we'll just select her firstName and hobbies.

Shell Command

db.pets.findOne({ firstName: 'Whiskey' }, { firstName: 1, hobbies: 1 });

Result

{
    "_id" : ObjectId("5c08c8c8abcff34df52dded2"),
    "firstName" : "Whiskey",
    "hobbies" : [
        "sleeping",
        "eating"
    ]
}

Notice that _id is always included in the result, because Mongo needs it.

Whiskey the Office Dog Being Lazy and Photogenic Whiskey the Dog

Now let's query animals that are less than 3 years old (sorry Whisk you poor old thing):

Shell Command

db.pets.find({ age: { $lt: 3 } });

Result

{ "_id" : ObjectId("5c08c8cfabcff34df52dded3"), "firstName" : "Gandalf", "species" : "owl", "age" : 1 }

Hopefully this syntax is relatively self-explanatory or at least intuitive once you start to play around with it. The $lt stands for "less than" operator. Here is a list of all the other query operators, and here is a guide to common queries (MongoDB's docs even include SQL equivalents).

Using MongoDB with Node.js

Let's jump right in to using MongoDB with Node.js and Express.js. I'm assuming you have Node.js downloaded and installed of course.

We're going to build the beginning of a RESTful JSON API just to see how easy it is!

Start a Node.js Project and Install Dependencies

The following commands are all standard for making a new Node/Express project (more info here):

mkdir pets_api
cd pets_api
touch index.js
npm init --yes
npm install express mongodb body-parser

The mongodb package is the MongoDB native driver for Node.js.

Express Server Starter Code

Here is the code for index.js (most of it was inspired from the official docs):

const express = require('express');
const bodyParser = require('express');
const MongoClient = require('mongodb').MongoClient;

// set up a connection to the server running on localhost (mongod)
const mongo = new MongoClient('mongodb://localhost:27017', {
  userNewUrlParser: true
});

// global variables app and db
const app = express();
let db;

// accept JSON request bodies
app.use(bodyParser.json());

/**
 * Route handler for GET to /pets
 */
app.get('/pets', function(req, res, next) {
  db.collection('pets') // query pets
    .find() // find all, view result as an array
    .toArray(function(error, result) {
      // a standard Node.js "error-first" callback
      if (error) {
        return res.json({ error });
      }
      // return the JSON of the result array
      return res.json(result);
    });
});

/**
 * Database connection and server set-up
 */
mongo.connect(function(error) {
  // a standard Node.js "error-first" callback
  if (error) {
    // kill express if we cannot connect to the database server
    console.error(error);
    process.exit(1);
  }

  // if we reach this line, we've made it
  console.log('Successfully connected to database');
  // set the active database
  db = mongo.db('pets_db');

  // standard express app.listen
  app.listen(3333, function() {
    console.log('Pets API Server listening on port 3333.');
  });
});

Run the server with the command node index.js from the terminal.

Remember that mongod always has to be running before you start your Express server.

Now if you navigate to your browser at http://localhost:3333/pets you should be able to see all the pets we inserted earlier!

A POST Handler to Insert Documents

What's great about MongoDB is that it stores documents in JSON format, which is also how we will POST data to our API. Let's look at a POST request handler:

app.post('/pets', function(req, res, next) {
  db.collection('pets').insert(req.body, function(error, result) {
    if (error) {
      return res.json({ error });
    }
    // inserts the request body directly into database
    return res.json(result);
  });
});

Now we will make a POST request to http://localhost:3333/pets with the following:

{
  "name": "Shadowfax",
  "species": "horse",
  "age": 1000
}

Plugging it into our handy Insomnia HTTP client we get the following:

Insomnia Request and Response

Wow! We didn't have to do any special data processing. We just sent JSON data and it went right into the database. The response format is a little "raw" right now, but it could easily be cleaned up.

If you send a GET request to /pets again, you can see good ol' Shadowfax has been added 🐴:

[
  {
    "_id": "5c08c8c8abcff34df52dded2",
    "firstName": "Whiskey",
    "lastName": "Lane",
    "species": "dog",
    "hobbies": ["sleeping", "eating"],
    "age": 4
  },
  {
    "_id": "5c08c8cfabcff34df52dded3",
    "firstName": "Gandalf",
    "species": "owl",
    "age": 1
  },
  {
    "_id": "5c08c8cfabcff34df52dded4",
    "firstName": "Socrates",
    "species": "cat"
  },
  {
    "_id": "5c08e115ed807d3aeebcfb52",
    "name": "Shadowfax",
    "species": "horse",
    "age": 1000
  }
]

Conclusion & Further Study

Summary

MongoDB is nice because of the ease of setting it up. If you know Node.js/Express.js and are comfortable with JSON, it should be no problem at all to dive in and start building servers. Because MongoDB handles JSON so well, there is very little processing needed if you're building a JSON API server. Also, because you don't need to define a schema, it can be a great choice as a data store for things like company take-home interview assignments (assuming they don't require a specific database). Learning MongoDB is also a great introduction to NoSQL / document stores for JavaScript developers.

Further Study

For the example code snippets above, I used old-school callback patterns to handle my async Node.js code. You can totally use ESNext features like async/await, and I recommend reading up on the examples in their documentation.

Lastly, I also used the lowest level MongoDB driver for Node.js, but a lot of people use a tool called Mongoose, self-styled as an "ODM" (Object-Document-Mapper) which also lets you overlay schemas (at the application level) on top of your MongoDB collections. This can help with validation, etc. We also still have a section on MongoDB in our free online curriculum, which I recommend checking out!

Written by Michael Michael

Back to all posts

Get Started with Rithm School