---
tags: ironhack, lecture,
---
<style>
.markdown-body img[src$=".png"] {background-color:transparent;}
.alert-info.lecture,
.alert-success.lecture,
.alert-warning.lecture,
.alert-danger.lecture {
box-shadow:0 0 0 .5em rgba(64, 96, 85, 0.4); margin-top:20px;margin-bottom:20px;
position:relative;
ddisplay:none;
}
.alert-info.lecture:before,
.alert-success.lecture:before,
.alert-warning.lecture:before,
.alert-danger.lecture:before {
content:"👨🏫\A"; white-space:pre-line;
display:block;margin-bottom:.5em;
/*position:absolute; right:0; top:0;
margin:3px;margin-right:7px;*/
}
b {
--color:yellow;
font-weight:500;
background:var(--color); box-shadow:0 0 0 .35em var(--color),0 0 0 .35em;
}
.skip {
opacity:.4;
}
</style>

# MongoDB | Shell & CRUD operations
## Learning goals
After this lesson, you will be able to:
- Use the MongoShell to Create, Read, Update and Delete Documents
## Intro

:::info lecture
CRUD
:::
When working with any Database, there are a few operations that we will always need to use. These operations are so popular that we have an acronym for it: [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) stands for `create`, `read`, `update` and `delete`:

These are the basic operations to persist data in our Database and with them, we can do anything we want. Ready?
## Quick Recap
### Database commands
We can launch the mongoShell by simply typing `mongo` in our terminal. Remember that each mongo server can hold many **databases**.
| Database Command | Explanation
|------------------|--------------
| `show dbs` | List all the databases inside our mongo server
| `use <dbName>` | This will switch to the database `dbName` or create it if it doesn't exist
| `db` | Show the name of the current database
### Collection commands
A Database is composed of different **collections**. This lesson will be focused on how to create, read, update and delete documents inside a collection. But first of all, let's take a look at a couple of useful collection commands:
| Collection Command | Explanation
|--------------------|--------------
|`show collections ` | List all the collections inside the current database
### JSON Documents
Each Collection is composed of different **documents**. A document is nothing more than a JSON object, with different **keys** and its associated values. We can identify a document by its `_id` property that mongo generates automatically for us.
**Example:**
```javascript
{
"_id" : ObjectId("58401d8b71caea72370262c1"),
"name" : "John Doe",
"age" : 25,
"address": {
"country": "Japan",
"address": "#901, 74-1 Yamashita-cho, Naka-ku"
}
}
```
## Create | Inserting Documents
Create commands allow us to insert new documents into a collection. If the collection doesn't exist, the operation will create it.
| Insert Command | Summary
|----------------|--------------------
| db.collection.insertOne(doc) | Adds a document to the collection
| db.collection.insertMany([docs]) | Adds one or more documents to the collection
### insertOne()
The [db.collection.insertOne](https://docs.mongodb.com/v3.2/reference/method/db.collection.insertOne/) command inserts a single document into the collection.
**Example:**
```javascript
> db.enemies.insertOne({
"name": "Blinky",
"color": "Red"
})
// The command returns an object with the following structure
//
// {
// "acknowledged" : true,
// "insertedId" : ObjectId("583c63f96fa7d619e2c574e6")
// }
```
:::info
**Notes**
- Since we don't have a collection called `enemies`, it will be created automatically
- As you can see, the document didn't have an `id`, so MongoDB created one for us
:::
**Another Example**
```javascript
> db.enemies.insertOne({
"_id": 10,
"name": "Pinky",
"color": "Pink",
"status": "alive"
})
// The command returns an object with the following structure
//
// {
// "acknowledged" : true,
// "insertedId" : 10
// }
```
Notice how the second document we inserted (`pinky`) has an extra field (`status`). MongoDB allows us to have a lot of flexibility with the schema, but we should be careful with it.
### insertMany()
[db.collection.insertMany()](https://docs.mongodb.com/v3.2/reference/method/db.collection.insertMany/) allows us to insert more than one document at the same time. `insertMany()` receives an array of documents as a paramater.
**Example**
```javascript
> db.enemies.insertMany([
{
"name": "Inky",
"color": "Cyan",
},
{
"name": "Clyde",
"color": "Orange"
}
])
// The command returns an object with the following structure
//
// {
// "acknowledged" : true,
// "insertedIds" : [
// ObjectId("583c645b6fa7d619e2c574e7"),
// ObjectId("583c645b6fa7d619e2c574e8")
// ]
// }
```
The return object will have a key `insertedIds`, which contains an array with the `ids` of the inserted elements
### About insert()
The [db.collection.insert()](https://docs.mongodb.com/v3.2/reference/method/db.collection.insert/) method inserts a single document in the same way that `insertOne()` does.
:::danger
:bomb: **Warning Notice**
The [insert](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#insert) method is deprecated (should not be used because it will be removed soon) in the **Node.js mongo driver**. You can use it in MongoShell, but we strongly recommend to use the `insertOne` and `insertMany` methods above in order to get used to the syntax.
:::
## Read | Finding/Listing Documents
The idea behind the read operation is that we should be able to retrieve `documents` from the database and read their contents. The basic method to find documents is [db.collection.find()](https://docs.mongodb.com/v3.2/reference/method/db.collection.find/) where you can specify two optional arguments:
:::info
`db.collection.find( <query_filter>, <projection> )`
:::
- `<query_filter>` an object that specifies which documents to return
- `<projection>` an object that allows us to return only certain fields from those documents

### Query Filters
#### Select all documents
To get all documents from a collection is as simple as specifying an empty object as the first argument.
```
> db.enemies.find({})
```
:::info
:bulb: If we only pass one argument we can omit the empty object. `db.enemies.find()` is the same as `db.enemies.find({})`
:::
#### Specify Equality Condition
Equality conditions will select all documents where the `<field>` matches the exact `<value>`
```
> db.collection.find({<field>: <value>})
```
**Example:**
```
> db.enemies.find({"name": "Blinky"})
```
:::warning
:cactus: Keep in mind that `<value>` is case sensitive, so `'Blinky'` is not the same as `'blinky'`.
:::
#### Advanced Conditions
We can specify conditions like greater than or less than, to do so we use query operators like:
```javascript
> db.collection.find(
{ <field>: { <operator>: <value>} }
)
```
Mongo provides us with a comprehensive list of [query operators](https://docs.mongodb.com/manual/reference/operator/query/), but for now, let's look at some of the most useful ones:
Mongo Operators | Description
:----------------:|-----------------
`$eq` | equal to
`$ne` | not equal to
`$gt` | greater than
`$gte` | greater than equal
`$lt` | less than
`$lte` | less than equal
**Example**
Imagine that we have a collection where documents have the following structure:
```javascript
[
{ name: "Popeye", age: 30 },
{ name: "Mickey Mouse", age: 35 },
{ name: "Batman", age: 24 }
]
```
If we want to select all the users who are older than 32 years, we can do the following query.
```
db.user.find({"age": { $gt: 32 }})
```
### Limiting Fields | Projections
The Find method's second argument, which we mentioned earlier, is called a [projection](https://docs.mongodb.com/v3.2/tutorial/project-fields-from-query-results/), and it allows us to specify which fields should be returned from each document in the result.
:::info
**Using projections makes our database queries faster**. When MongoDB has to retrieve less fields, it's less work for the computer to do and less information to transfer over the network so the query takes less time.
:::
Let's see how to use the projection.
The projection must be an object with either:
- All the fields we want to include (set them to `1`)
- All the fields we want to exclude (set them to `0`)
The projection cannot combine `0` and `1` at the same time except for the `_id` that can be `0` when others are `1`.
:::warning
By default "_id" is set to `1`, so if we don't want to show it we have to specify `_id: 0`.
:::
Example:
```javascript
> db.enemies.find({},{
"name": 1,
"_id": 0
})
```
As you can see we specified as a projection {`"name": 1`, `"_id": 0`}. Mongo will return the `name` property of each documents, but not their `_id`:
```javascript
{ "name" : "Blinky" }
{ "name" : "Pinky" }
{ "name" : "Inky" }
{ "name" : "Clyde" }
```
### Independent Practice
Let's introduce the following documents to our database so that we can all start with the same data.
```javascript
{
name: "Sue",
age: 19,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "2342"
},
privileges: "user",
favorites: { artist: "Picasso", food: "pizza" },
finished: [ 17, 3 ],
badges: [ "blue", "black" ],
points: [
{ points: 85, bonus: 20 },
{ points: 85, bonus: 10 }
]
},
{
name: "Bob",
age: 42,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "7673"
},
privileges: "admin",
favorites: { artist: "Miro", food: "meringue" },
finished: [ 11, 25 ],
badges: [ "green" ],
points: [
{ points: 85, bonus: 20 },
{ points: 64, bonus: 12 }
]
},
{
name: "Willy",
age: 22,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "8263"
},
privileges: "user",
favorites: { artist: "Cassatt", food: "cake" },
finished: [ 6 ],
badges: [ "blue", "Picasso" ],
points: [
{ points: 81, bonus: 8 },
{ points: 55, bonus: 20 }
]
},
{
name: "John",
age: 34,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "2143"
},
privileges: "admin",
favorites: { artist: "Chagall", food: "chocolate" },
finished: [ 5, 11 ],
badges: [ "Picasso", "black" ],
points: [
{ points: 53, bonus: 15 },
{ points: 51, bonus: 15 }
]
},
{
name: "Steve",
age: 23,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "8253"
},
privileges: "user",
favorites: { artist: "Noguchi", food: "nougat" },
finished: [ 14, 6 ],
badges: [ "orange" ],
points: [
{ points: 71, bonus: 20 }
]
},
{
name: "Martin",
age: 43,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "5623"
},
privileges: "user",
favorites: { food: "pizza", artist: "Picasso" },
finished: [ 18, 12 ],
badges: [ "black", "blue" ],
points: [
{ points: 78, bonus: 8 },
{ points: 57, bonus: 7 }
]
}
```
Open your mongoshell, introduce the documents above in the collection `employees` and perform the following queries:
- List all the employees
- Find the employee with whose name is Steve
- Find all employees whose age is greater than 30
- Find the employee whose extension is 2143
*(Should take approximately 10 minutes)*
## Update commands
The update command allows us to update some fields in the document or replace all document:
| Mongo Method | Description
|--------------|---------------------
| [`db.collection.updateOne(<filter>, <update>)`](https://docs.mongodb.com/v3.2/reference/method/db.collection.updateOne/) | Updates a single document within the collection
| [`db.collection.updateMany(<filter>, <update>)`](https://docs.mongodb.com/v3.2/reference/method/db.collection.updateMany/) | Updates multiple documents within the collection
| [`db.collection.replaceOne(<filter>, <update>)`](https://docs.mongodb.com/v3.2/reference/method/db.collection.replaceOne/) | Replaces a single document within the collection
All these methods accept two parameters:
- `<filter>` finds what documents to update (same as [query filters](https://hackmd.io/mGLw7B34Q7a0GfnaaqfQmw#Query-Filters))
- `<update>` specifies what fields to update in the document
:::info lecture
Bien se référer à la [doc Mongo](https://docs.mongodb.com/v3.2/reference/method/db.collection.updateOne/).
:::
### updateOne()
[db.collection.updateOne()](https://docs.mongodb.com/v3.2/reference/method/db.collection.updateOne/) updates a single document that matches the specified filter.
:::warning
:warning: If we have more than one document that matches that filter, this operation will update only one.
:::
Following with the collection `employees`, let's update the user `"Martin"` with his new extension number.
```javascript
db.employees.updateOne(
{ "name": "Martin"},
{ $set: { "phone.ext": 1234 }}
)
```
This function will return an object where `"matchedCount"` is how many documents satisfy the filter and `"modifiedCount"` is how many documents were updated.
:::warning
:warning: Notice that when we need to access nested objects like the `ext` field inside `phone`, we need to use dot notation like JavaScript objects. They have to be in double quotes: `"phone.ext"`:
```javascript
{
name: "Martin",
age: 43,
phone: {
personal: "555-123-123",
work: "555-456-456",
ext: "5623"
},
privileges: "user",
favorites: { food: "pizza", artist: "Picasso" },
finished: [ 18, 12 ],
badges: [ "black", "blue" ],
points: [
{ points: 78, bonus: 8 },
{ points: 57, bonus: 7 }
]
}
```
:::
```javascript
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
```
**Your turn!** Try to update the age of Sue to 20.
### updateMany()
[db.collection.updateMany()](https://docs.mongodb.com/v3.2/reference/method/db.collection.updateMany/) updates all documents that match the specified filter.
We want to update all employees older than 30 so that their favourite writer is Cervantes.
```javascript
db.employees.updateMany(
{ "age": { $gte: 30 }},
{ $set: { "favorites.writer": "Cervantes" }}
)
```
Result:
```javascript
{ "acknowledged" : true, "matchedCount" : 3, "modifiedCount" : 3 }
```
### replaceOne()
[db.collection.replaceOne()](https://docs.mongodb.com/v3.2/reference/method/db.collection.replaceOne/) replaces the first document that matches the specified filter even if there are more than one.
Our employee `"Martin"` is not working anymore in our company so let's replace him for our new employee `"Susan"`.
The new document for `"Susan"`
```javascript
var susan = {
"name" : "Susan",
"age" : 25,
"phone" : { "personal" : "555-223-223", "work" : "555-421-426", "ext" : 4240 },
"privileges" : "user",
}
db.employees.replaceOne(
{ "name": "Martin"},
susan
)
```
:::info
:bulb: Replacing a document does not change its `_id` value. The `_id` field is immutable. If we include it in the new document it must have the same value as before.
:::
## Delete commands
The delete commands remove documents from our collections.
### deleteOne()
```javascript
db.employees.deleteOne( { "_id": ObjectId("583ea82c58613b64d5df8405") })
```
### deleteMany()
If we want to remove **all** documents
```javascript
db.employees.deleteMany({})
```
Removes the documents that match the filter criteria.
```javascript
db.employees.deleteMany({ age : { $gte: 30 }})
```
## Independent Practice
Now that you know how to insert, delete, query and update documents, let's practice!
- Find all employees that are over 30.
- Find all employees that are less than or equal to 30.
- Find all the employees whose favorite food is pizza.
- Change Willy's personal phone number to "93-123-45-67".
- Change Bob's privilege to normal user.
- Find all employees whose favorite artist is equal to Picasso.
- Delete the user John.
- (EXTRA) Add a bonus of 15 to all those who have a bonus less than 10.
## Summary
In this lesson we learnt how to perform basic operations with MongoShell.
## Extra Resources
- [Mongo CRUD Documentation](https://docs.mongodb.com/v3.2/crud/)
- [Query selectors in MongoDB](https://docs.mongodb.com/v3.2/reference/operator/query/#query-selectors)
- [Reference Operators](https://docs.mongodb.com/v3.2/reference/)