Skip to main content

Mongo Database

Lesson Objectives#

  1. Describe what is a Database
  2. Describe what is Mongo
  3. Understand the difference between a Mongo database, sub-database, collection, and document
  4. Get Mongo running
  5. List sub-databases
  6. choose a sub-database
  7. create a collection
  8. insert a document
  9. insert multiple documents
  10. query the collection
  11. remove a set of documents
  12. update a set of documents
  13. drop a Collection or sub-database

What is a Database#

A database is an organized collection of data, stored and accessed electronically.

For our CRUD apps so far we've been hard coding some data. We've been able to make temporary changes, but as soon as we shut down our servers, those changes are gone.

We need a way to make our data persist.

We'll do that by storing/accessing our data from a database.

There are many databases. A common type is a SQL(Structured Query Language) database which stores data in tables and rows, much like an excel spreadsheet/google sheet.

Another type of database is a NoSQL(Not Only SQL) database, which follows a different structure. In our case, we'll be using MongoDB which will store our data in objects (just as we've been seeing with our mock databases)

What is Mongo#

MongoDB is a database that holds JavaScript Objects. The database itself is an application that runs quietly on a computer and waits for connections that make requests and then sends responses (much like a web server).

Mongo is designed to be a database that is flexible and easily scalable.

Our Cheatsheet

Mongo Sub-Databases#

You can have multiple smaller databases stored and available in Mongo.

Imagine a company like Google, they would have multiple databases: one for mail, one for maps, one for drive documents...

For us, we'll have multiple sub-databases, typically one for each lesson, homework and project.

Here is a way you COULD split up sub-databases for an app

sub database example

Mongo Collections and Documents#

MongoDB is considered a NoSQL (not only SQL, non SQL or non relational), rather than storing things in tables with rows and columns, NoSQL databases use other means. In the case of MongoDB, data is stored in JavaScript objects.

A collection is a set of documents. Documents are a set of data records. This is very abstract. Let's use a simplified real world example of an address book.

Here is one document:

 firstName: "Jennifer", lastName: "Juniper", address: "Upon the Hill", state: "California", telephone: "867-5309", birthday: "June 8, 1968", email: "jenny.juniper@juno.net"

A collection, would be many documents: In our case, many contacts.

Remember: having a collection of documents sounds quite reasonable. But having a document of collections is ... kind of odd.

If you're coming from a background where you are used to thinking of data in terms of columns and rows, reading the following could be helpful in transitioning into this new way of modeling data:

Thinking in Documents Part 1

Thinking in Documents Part 2

Install Mongo#

We already installed Mongo, if you need to reinstall, follow the directions here

Get Mongo Running#

Let's use three 3️⃣ terminal tabs. One 1️⃣ to keep bash open and available, open a new one 1️⃣ to start mongod and one 1️⃣ more to run the mongo shell.

In terminal, type mongod

A bunch of text should come up, but in version 3.6.3, the final line says

last line of successful mongod

Server is Running All the stuff

mongod running successfully

Connect to Mongo#

There are a few ways to connect to Mongo. In this course, there will be two main ways:

  • Through terminal in a shell
  • Through node using an npm module called mongoose

Connect via Mongo Shell#

Open a second terminal tab (do not shut mongod tab down), (shortcut key: command t)

type mongo

A bunch of text should come up, but in version 3.6.3, the final line should have changed from a bash prompt $ to a >

Mongo Shell Ready to type

Mongo Shell is Running All the stuff

mongo running successfully

Connect/Create to a Sub-Database#

Let's keep working on our Mongo Shell.

Let's see what sub-databases we have available to us:

show dbs

Sample Appearances of Sub Databases

Sample Appearances of Sub Databases

We want to create and use a sub-database called learn. With Mongo, if it doesn't exist, Mongo will create it.

Therefore if we type

use learn

It will create a sub-database called learn and connect to it

Created and Connected to Learn sub-databases

create and connect to learn

It is likely that our configuration let's us see the db name at our prompt, but in case it doesn't or we want a reminder we can type

db

To see the database we are currently connected to.

Create a Collection#

For today, we'll only be working with one collection, but most apps will have numerous collections.

Let's think about an online store. You might split up the collections like so:

- users    - username    - password    - address    - creditCardInfo    - phoneNumber
- products    - productName    - catalogNum    - imageLink    - price    - inStock

This helps us organize our data.

Let's go back to our address book example and create a collection of contacts.

db.createCollection('contacts')

We should get an ok message, if we've done it correctly.

Created a new collection successfully

collection create

We can see what collections we have by typing

show collections

Create, Read, Update and Delete Documents#

We've been creating, reading, updating and deleting our 'data' in our Express apps. Now let's learn how to do it using Mongo.

Remember: users are not going to open a Mongo shell and type everything we're going to type. We'll eventually be building apps to interact with our database.

Insert a document into a Collection (Create)#

We'll use the insert() method. We have to tell mongo where to insert it. We'll do that by chaining it to db.contacts It takes two arguments. The first is always an object of our data. The second is optional and can let us choose some specific options.

Insert into contacts:

db.contacts.insert()

Pass in an object as the first argument

db.contacts.insert({})

Add some key value pairs, for Jennifer. We're going to split it up across multiple lines to make it easier to type and see

db.contacts.insert({  name: 'Jennifer',  phone: 8675309,  state: 'California'})

We can also type our code in atom and when we know it's right, copy and paste it over into our Mongo shell. Go with whatever is easier.

Successful insert

Successful insert

Let's go ahead and copy paste this into our Mongo shell to populate our collection with more documents

db.contacts.insert(  [    {      name: 'Jennifer',      phone: 8675309,      state: 'California'    },    {      name: 'Claire',      phone: 6060842,    },    {      name: 'Morris',      phone: 7779311,      state: 'Minnesota'    },    {      firstName: 'Alicia',      lastName: 'Keys',      phone: 4894608,      state: 'New York'    },    {      name: 'Etta',      phone: '842-3089',      state: 'California'    },  ])
Successful insert many

Successful insert many

We may notice that our data wasn't consistent.

  • Jennifer has a duplicate record
  • Claire, doesn't have a state
  • Alicia's key's are different for her name than others, she also has an extra field for her last name, compared to others.
  • Etta's phone number is a string with a hyphen instead of a number

Mongo is designed to be this flexible. Later, we'll learn how to validate our data with an npm package called mongoose.

Query Documents from a Collection(READ)#

We'll use the .find() method.

We'll do some simple queries. If we provide no argument, it will find all the documents.

Let's try it

db.contacts.find()

We may find that to not be as human-readable as we'd like, we can chain another function on it

db.contacts.find().pretty()
Successful find all

Find All

Many times, we don't want to find all.

We might want to just find the names of the people who live in California.

We can give our .find() method some arguments. The first argument will be a filter and the second argument will be a projection the project will be the key, it can have a value of 0 (do not show this field) or 1 (do show this field).

When we skip the second argument, we see the whole document:

db.contacts.find({ state: "California" }).pretty();

Let's look for the names of people who are in the state of California, and let's not show the _id field. We'll add a second argument.

db.contacts.find({ state: "California" }, { name: 1, _id: 0 }).pretty();

Remove Documents from a Collection(DELETE)#

Let's remove that duplicate record. We'll use a method called .remove(), it takes two arguments, the first is a query (what document are we looking for? - Jennifer's), the second one gives us options

db.contacts.remove({  name: "Jennifer",});
Ooops two records removed

removed two records, oops

Let's put Jennifer back again twice:

db.contacts.insert({  name: "Jennifer",  phone: 8675309,  state: "California",});db.contacts.insert({  name: "Jennifer",  phone: 8675309,  state: "California",});

We should see we did it successfully with the message that we get.

But we can also run a query:

db.contacts.find({ name: "Jennifer" }).pretty();

And Let's try to remove again. This time we're going to pass a second argument that will be an object that has the key values of justOne: true

db.contacts.remove(  {    name: "Jennifer",  },  { justOne: true });

We should have a success message that reads like the following:

Removed 1 record(s) in 2msWriteResult({  "nRemoved": 1})

Let's use our UP arrow ⬆️ to scroll back to our .find() for Jennifer and check that we now have just one record.

db.contacts.find({ name: "Jennifer" }).pretty();

Update a document (Update)#

Like .remove(), update takes a query for what to update. But it is also REQUIRED to use an update operator as part of the second argument in order to prevent destroying our object.

Let's update Jennifer's record to have the name Jenny instead

db.contacts.update({ name: "Jennifer" }, { name: "Jenny" });

Success looks like this:

Updated 1 existing record(s) in 35msWriteResult({  "nMatched": 1,  "nUpserted": 0,  "nModified": 1})
  • we have number matched (nMatched) equal to 1
  • we have number upserted (nUpserted) equal to 0 (upsert means if it doesn't exist, create it, we did not create anything this time)
  • we have number modified (nModified) equal to 1, which means we modified 1 records.

Let's push the up arrow and run our last command again:

db.contacts.update({ name: "Jennifer" }, { name: "Jenny" });

This time we get:

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

We have no matches, no upserts and nothing modified. This is what we expect, since we changed this record the first time we ran it.

Let's find Jenny

db.contacts.find({name:'Jenny'})

We lost the rest of Jenny's record!

Jenny's Destroyed record

This is because we didn't use an update operator. In order to keep our data intact with an update we must use an update operator.

Let's remove and reinsert Jenny's record and try again

db.contacts.remove({  name: "Jenny",});
db.contacts.insert({  name: "Jennifer",  phone: 8675309,  state: "California",});

Let's use the $set update operator this time

db.contacts.update(  { name: "Jennifer" },  {    $set: { name: "Jenny" },  });

Since our data set is very small, let's just look at all of our records

db.contacts.find().pretty();

We can add a field. Claire has no state, let's give her a state

db.contacts.update(  { name: "Claire" },  {    $set: { state: "California" },  });

We can push the up arrow ⬆️ to rerun

db.contacts.find().pretty();

And we should see that Claire now has a state, so we don't have to query for the field that we want to change, we can query for any match.

Because of this, our objects can be ever changing. The way we can reliably be sure we are always getting the right document, is to use the unique id number attributed to each document on creation. Typing these long ids are tough for a code along, but when we start making our express CRUD apps, we'll definitely be using the id numbers a lot.

By default, update will only update one record

db.contacts.update({}, { $set: { bestFriend: true } });

Press the up arrow ⬆️ to run

db.contacts.find().pretty();

As we can see, just one record was updated. Let's try to update all of our records, by adding a third argument to our .update() method

db.contacts.update({}, { $set: { bff: true } }, { multi: true });

Press the up arrow to run

db.contacts.find().pretty();

Search for Multiple Values#

We can query for multiple values. In our contacts, let's query for people who live in California and are named Etta

db.contacts.find({  name: "Etta",  state: "California",});

Search by Quantitative Data#

We can search for equal to, not equal to, greater than, less than or equal to, included in an array etc.

query operators

Let's just try one together. Let's query for the people who are NOT in California

db.contacts.find({  state: { $ne: "California" },});

Drop a collection#

If you need to remove an entire collection

db.contacts.drop();

If you need to drop an entire sub-database, while you are connected to the database you want to drop:

db.dropDatabase();

Remember to quit out of Mongo and Mongo Shell when you are done#

To quit out of the Mongo shell type exit

To quit out of Mongo, press control c

Bonus Configuration#

Update your mongo shell to always show pretty

Anywhere in bash

echo DBQuery.prototype._prettyShell = true >> ~/.mongorc.js

Turn it off

echo DBQuery.prototype._prettyShell = false >> ~/.mongorc.js

Don't turn it off and on this way repeatedly. Take the time to google and find out more about the config file and how to update it and change your configs.