Mongo Database
#
Lesson Objectives- Describe what is a Database
- Describe what is Mongo
- Understand the difference between a Mongo database, sub-database, collection, and document
- Get Mongo running
- List sub-databases
- choose a sub-database
- create a collection
- insert a document
- insert multiple documents
- query the collection
- remove a set of documents
- update a set of documents
- drop a Collection or sub-database
#
What is a DatabaseA 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 MongoMongoDB 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.
#
Mongo Sub-DatabasesYou 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
#
Mongo Collections and DocumentsMongoDB 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:
#
Install MongoWe already installed Mongo, if you need to reinstall, follow the directions here
#
Get Mongo RunningLet'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
Server is Running All the stuff
#
Connect to MongoThere 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 ShellOpen 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 is Running All the stuff
#
Connect/Create to a Sub-DatabaseLet'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
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
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 CollectionFor 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
We can see what collections we have by typing
show collections
#
Create, Read, Update and Delete DocumentsWe'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
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
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
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
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!
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 ValuesWe 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 DataWe can search for equal to, not equal to, greater than, less than or equal to, included in an array etc.
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 collectionIf 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 doneTo quit out of the Mongo shell type exit
To quit out of Mongo, press control c
#
Bonus ConfigurationUpdate 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.