README.md |
This are my personal notes for MongoDB. If something is unaccurate please let me know.
Concepts
Databases
- A container of collections
- Each database has it own filesystem
- A cluster can have multiple databases
Collections
- A group of documents
- It's similar to the tables on a relational database
- Doesn't need a schema
Documents
- An entry of a document
- Similar to JSON (BSON (binary JSON))
- Basic unit inside MongoDB
- They can't be more than 16MB
Drivers
Libraries that we use to communicate from our programming language to the database. For example the Mongo drivers for Node.js
Traversal startup for most languages
Create MongoClient connection -> Get MongoDatabase -> get a collection -> CRUD
Data types
ObjectId
:ObjectId("6141fc6e672cb3a30ee6711d")
String
:"Some text"
Boolean
:True
|False
Date
:ISODate("2020-02-18T")
Number
:Double
,Integer 32 bits
,Integer 64 bits
,Decimal
Embedded sub-document
:{}
Arrays
:[]
More types
Schemas and relations
Mongo doesn't require schema or relations but if you need to, you can have them.
One-to-many
could be an ID that points to another ID but this is way too "SQL" style. The other approach is to have an embeded document.
Many-to-many
is also the same concept but with arrays.
The issue is that we might have to update each embedded document in case some information changes. It is better to use references in this case.
More about relationships here
You can also have JOIN-like queries with $lookup
, learn more here
Projections
Sometimes we don't need the whole document, just a few data, so we can select just the data we need in the second parameter like so:
> db.pokemons.findOne(
{_id: ObjectId("ABC...")}, // Filter
{ // Projection
name: 1
}
)
Will return:
{ "_id" : ObjectId("6141fc6e672cb3a30ee6711d"), "name" : "Pikachu" }
The _id
will be always selected by default. If we don't want the _id
we can specify _id: 0
Operators
Syntax:
{ <field1>: {<operator1>: <value1>}, ... }
Example:
> db.pokemons.find({type: {$in: ["grass", "fire"]}})
Where $in
is the operator
Comparison operators:
$eq
:=
$gt
:>
$gte
:>=
$lt
:<
$lte
:<=
$ne
:!=
$in
: Values inside of an array$nin
: Values NOT inside of an array Logical operators:$and
: Logical AND$or
: Logical OR$not
: Logical NOT$nor
: Logical NOT OR Element operators:$exist
: Documents that have an specific field$type
: Documents that have an specific field type Array operators:$all
: Array that have all specified values$elemMatch
: Query for arrays containing sub-documents$size
: Arrays with specific length More operators here
Commands
Connect to your local mongo instance:
mongo
Connect to a remote instance
mongo "mongodb+srv://HOST:PORT/DATABASE" --username yourusername
It will prompt for your password
Show the databases
> show dbs
Switch to the "gamefreak" database
> use gamefreak
Show the current database
> db
Show the collections of the current database
> show collections
Get help of the commands of the collection
> db.pokemons.help()
Insert to the "pokemons" collection.
If the collection doesn't exists, Mongo will create it.
> db.pokemons.insertOne({
name: "Pikachu",
pokedexId: 1,
type: ["electric", "normal"]
})
And it will return something like this:
{
"acknowledged" : true,
"insertedId" : ObjectId("6141fc6e672cb3a30ee6711d")
}
You could specify an _id
, but it's a good practice to leave Mongo to create it own ID, since they must be unique.
Insert many
> db.pokemons.insertMany([
{
name: "Bulbasaur",
pokedexId: 2,
type: ["plant"]
},
{
name: "Charmander",
pokedexId: 3,
type: ["fire"]
},
])
Will return something like:
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("61420dea672cb3a30ee6711e"),
ObjectId("61420dea672cb3a30ee6711f")
]
}
Update
First parameter is the filter and the second is the data
> db.pokemons.updateOne(
{_id: ObjectId("61420dea672cb3a30ee6711e")}, // Filter
{ // data
$set: {
level: 50
}
}
)
Will return:
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
You can also use .update()
to update many instead of just one
Updating arrays
We can use $addToSet
to insert a value into an array and $pull
to remove it
> db.pokemons.updateOne(
{_id: ObjectId("61420dea672cb3a30ee6711e")}
{
$addToSet: {type: "normal"}
}
)
Will result in:
{
"_id" : ObjectId("61420dea672cb3a30ee6711e"),
"name" : "Bulbasaur",
"pokedexId" : 1,
"type" : [
"plant",
"normal"
],
"level" : 50
}
And using $pull
instead results in:
{
"_id" : ObjectId("61420dea672cb3a30ee6711e"),
"name" : "Bulbasaur",
"pokedexId" : 1,
"type" : [
"plant"
],
"level" : 50
}
Delete
.deleteMany()
or .deleteOne()
will receive one parameter which is the filter
> db.pokemons.deleteOne({_id: ObjectId("61420dea672cb3a30ee6711e"))
Finding
Find many (the .find()
could be empty if you want to fetch all)
with the specified condition. The .pretty()
is not necessary, is just for a better visual.
> db.pokemons.find({pokedexId: 1})
Will return
{
"_id" : ObjectId("6141fc6e672cb3a30ee6711d"),
"name" : "Pikachu",
"pokedexId" : 1
}
{
"_id" : ObjectId("61420dea672cb3a30ee6711e"),
"name" : "Bulbasaur",
"pokedexId" : 1,
"type" : [
"plant"
]
}
Find one on the "pokemons" collection.
> db.pokemons.findOne()
You can also specify filters. It's important to specify the ObjectId
> db.pokemons.findOne({_id: ObjectId("6141fc6e672cb3a30ee6711d")})
Returns:
{
"_id" : ObjectId("6141fc6e672cb3a30ee6711d"),
"name" : "Pikachu",
"pokedexId" : 1
}
AND operation
Find the pokemon with a level lower than 50
> db.pokemons.find({
level: {
$lte: 50
}
})
$lte
: Less than
It will return null
if nothing was found
Count the documents returned
> db.pokemons.find({pokedexId: 1}).count()
Returns:
2
.limit(), .skip() and .sort()
This doesn't need that much explanation, it works similar to SQL's LIMIT, OFFSET and ORDER BY
> db.pokemons.find({}).limit(10).skip(10).sort({pokedexId: "desc"})
Aggregations $match, $group, $sum, $avg, $multip
You can create complex queries with aggregations Example if we want to group by level:
> db.pokemons.aggregate([
{
$match: { // This is kinda like the "SQL WHERE". Here will be the filters
$or: [{name: "Bulbasaur"}, {name: "Charmander"}]
}
},
{
$group: { // GROUP BY name and SUM the levels
_id: "$name",
total: {$sum: "$level"}
}
}
])
Returns:
{ "_id" : "Bulbasaur", "total" : 10 }
{ "_id" : "Charmander", "total" : 20 }