{ Introduction to NoSQL. }

Objectives:

By the end of this chapter, you should be able to:

  • Compare and contrast SQL and NoSQL databases
  • Install Mongo and start a Mongo Server
  • Perform CRUD operations in a Mongo console

So far we have been using an array to store our data. Since this array is being stored in memory on the server, it only lasts as long as our server is running. The second our server goes down, we lose all our data! This simply will not work for any practical application. At some point, we will need to be able to save, or persist, our data to a hard drive. To do that, we'll need to use a database.

NoSQL vs SQL

The database we will be using is MongoDB, which is a NoSQL database. To understand what that means, however, we first need to understand what a SQL database is. SQL databases store tables of data; and inside each table, the rows (also called records) are structured based on a predefined schema.

What does this mean? Let's consider a simple example. Suppose you have a simple blogging application, where users can log in and write posts. In a SQL database, this might mean you have two tables:

  1. The first table would be for users. Each row in the table would contain data for a single user, such as their email address, their name, and so on.
  2. The second table would be for posts. Each row would store the text of a post, the date it was created, and so on. You'll also probably want to store a reference to the author who wrote the post.

Furthermore, the tables in SQL databases are called "relational" because they are designed to cross-reference each other. The term RDBMS refers to "Relational DataBase Management System", examples of which are: MySQL or PostgreSQL. For a comprehensive introduction to SQL, visit our curriculum on SQL in the Flask Fundamentals section.

In contrast with SQL databases which have relational, schema-based tables, NoSQL databases are non-relational and many do not store data in table form. For a great overview of SQL vs. NoSQL, click here.

MongoDB

MongoDB is a very popular NoSQL database engine. It stores collections of schemaless documents in BSON form (essentially binary JSON). MongoDB query syntax is very similar to JavaScript and can easily be converted to pure JS. Because MongoDB stores JSON-like documents and queries them with JavaScript, it is a natural choice for a database when developing with Node or Express. For a more complete introduction, head here.

Installing MongoDB

Depending on your OS - here are instructions to install MongoDB.

  1. For Mac OSX, this guide is probably the easiest; or you can check out the official instructions here.
  2. For Windows, you can read how to install it here, here, or using the official guide here.
  3. Instructions for Ubuntu/Linux can be found here.

Essential Terms

Now that we have MongoDB installed let's review some essential terms:

database - this is where all of our data is stored. We can create multiple databases, and each database will store multiple collections.
collection - collections are aggregations of documents. Each document can have any number of attributes because collections do not enforce a schema.
document - documents are JSON-like objects that contain all types of information. They can have any valid JSON data type (e.g. String, Number, Array, Object).

In the language of MongoDB, we wouldn't say that we have a table of data on users, where each row corresponds to one user. Instead we'd say that we have a collection of user documents, where each document corresponds to one user.

Remember these user documents do not need to have a common structure: one user could have an email address and a first name, another could have a last name and an address, and a third could have an entirely different set of data being stored.

Database Commands

To perform database operations in mongo, start up a mongo server by typing mongod in the terminal (unless you started the mongodb service in the background using homebrew, for instance).

Then open up a new tab and enter the MongoDB shell by typing mongo.

Here are some essential database commands:

  • show dbs will display a list of all available databases.
  • use test lets you switch to a database called test. If that database does not exist, it will be created by this command.
  • db.getCollectionNames() lists collections that have already been created
  • db.dropDatabase() deletes the current database and all its collections.

In MongoDB, collections are created on-the-fly as soon as you insert documents into them, which we'll get into below!

CRUD

Here is a list of the most commonly-used CRUD operations in MongoDB with examples. For a full list, check out the MongoDB docs here.

Create

To create in mongo we use the insert function, which belongs to a collection we are operating on. insert accepts an object of keys and values.

You can also insert an array of objects using the insertMany function.

db.users.insert({
  first: "Elie",
  last: "Schoppik",
  isInstructor: true,
  favoriteColors: ["Green", "Blue", "Purple"],
  favoriteFood: "sushi"
});

db.users.insert({
  first: "Mary",
  last: "Malarkin",
  isInstructor: false,
  favoriteColors: ["Green", "Yellow"],
  hometown: "Omaha"
});

db.users.insertMany([
  { first: "Tim", funFact: "owns a boat!" },
  { first: "Matt", funFact: "has a pet dog!" }
]);

Read

To query documents in mongo, we use the find command to find multiple objects and findOne for a single one.

db.users.find();
/*
{ "_id" : ObjectId("5a288cc40189b2bedb2967f9"), "first" : "Mary", "last" : "Malarkin", "isInstructor" : false, "favoriteColors" : [ "Green", "Yellow" ], "hometown" : "Omaha" }
{ "_id" : ObjectId("5a288de60189b2bedb2967fb"), "first" : "Elie", "last" : "Schoppik", "isInstructor" : true, "favoriteColors" : [ "Green", "Blue", "Purple" ], "favoriteFood" : "sushi" }
{ "_id" : ObjectId("5a288e2b0189b2bedb2967fc"), "first" : "tim", "funFact" : "owns a boat!" }
{ "_id" : ObjectId("5a288e2b0189b2bedb2967fd"), "first" : "matt", "funFact" : "has a pet dog!" }
*/

The first argument to find/findOne is an object that contains a key-value query. For example, if you want to query users whose first name is "Mary" you would type:

db.users.findOne({ first: "Mary" });
/*{
  "_id": ObjectId("58aa39cb62a53c60f58471c7"),
  "first": "Mary",
  "last": "Malarkin",
  "isInstructor": false,
  "favoriteColors": [
    "Green",
    "Yellow"
  ],
  "hometown": "Omaha"
}
*/

Note: if there are multiple matches, findOne returns the first entry (usually first inserted).

The second argument to find/findOne is an object that contains which fields to return, in case you don't need all of the fields. For example, if you just wanted to return Elie's favorite food, your query would look like this:

db.users.findOne(
  // query by first and last name
  { first: "Elie", last: "Schoppik" },
  // give us only the "favoriteFood" field
  { favoriteFood: 1 }
);
/*
{ "_id" : ObjectId("5a288de60189b2bedb2967fb"), "favoriteFood" : "sushi" }
*/

Note: _id is always returned by default.

Tip: you can use the .pretty() method to return a nicer-looking list of documents. Here is an example query for users who have "Green" as a favorite color:

db.users.find({ favoriteColors: "Green" }).pretty();
/*
{
    "_id" : ObjectId("5a288cc40189b2bedb2967f9"),
    "first" : "Mary",
    "last" : "Malarkin",
    "isInstructor" : false,
    "favoriteColors" : [
        "Green",
        "Yellow"
    ],
    "hometown" : "Omaha"
}
{
    "_id" : ObjectId("5a288de60189b2bedb2967fb"),
    "first" : "Elie",
    "last" : "Schoppik",
    "isInstructor" : true,
    "favoriteColors" : [
        "Green",
        "Blue",
        "Purple"
    ],
    "favoriteFood" : "sushi"
}
*/

Update

To update documents in mongo, we use the update method. The first argument is the query to select the appropriate documents; the second argument is the actual keys and values to update:

db.users.update(
  // what to find the user by
  { first: "Tim" },
  // what data to update
  {
    first: "Michael",
    moreInfo: "Is a new instructor",
    favoriteNumbers: [11, 111, 1111]
  }
);

/*
WriteResult({
  "nMatched": 1,
  "nUpserted": 0,
  "nModified": 1
})
*/

We can also use update to add a new document, if we pass it the upsert option! upsert is a portmanteau of update and insert. When you upsert into a collection, a document will be updated if it is found, and inserted if no matching document is found.

db.users.update(
  { name: "fjlsadkdfjsdaklfjdklsajfklds" },
  {
    name: "Upsert will insert if it can not find!",
    moreInfo: "How cool is that?",
    favorite_numbers: [11, 12, 13]
  },
  // if it is not found, insert it! (upsert = update or insert)
  { upsert: true }
);

/*
WriteResult({
  "nMatched": 0,
  "nUpserted": 1,
  "nModified": 0,
  "_id": ObjectId("58aa3a859c4f01de70dcd04b")
})
*/

Finally, if you want to update multiple documents, you can set multi equal to true.

// update every single one that is found using multi:true
db.users.update(
  // find all where the name is not equal to 'nope'
  { name: { $ne: "nope" } },
  // set a new key of isHilarious to true
  { $set: { isHilarious: true } },
  // for more than 1 record
  { multi: true }
);

/*
WriteResult({
  "nMatched": 4,
  "nUpserted": 0,
  "nModified": 4
})
*/

For more on update, check out the docs.

Delete

To delete documents in mongo, we use the remove method.

// remove a single user
db.users.remove({ name: "Bob" });
/*
Removed 0 record(s) in 1ms
WriteResult({
  "nRemoved": 1
})
*/

// remove all the users
db.users.remove({});
/*
Removed 1 record(s) in 2ms
WriteResult({
  "nRemoved": 3
})
*/

Additional Find Methods

Since the process of deleting or updating involves first finding a record, we can use some built-in methods to perform both operations at once.

db.users.findAndModify({
  // find someone with a name of elie and a score greater than 10
  query: { name: "Elie", score: { $gt: 10 } },
  // increment their score by 1
  update: { $inc: { score: 1 } }
});

db.users.findOneAndUpdate({ name: "Elie" }, { $inc: { points: 5 } });

db.users.findOneAndDelete({ name: "Elie" });

You can read more about the difference between modify and update here. And for documentation on all of these methods (and others we haven't discussed), go here.

Screencast

Here is a screencast to get up and running with MongoDB:

When you're ready, move on to MongoDB with Mongoose

Continue

Creative Commons License