From 95909936ef9f95e980999dd4b21d63288ec146ef Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Wed, 15 Sep 2021 12:19:11 -0500 Subject: [PATCH] First commit --- README.md | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9bee53 --- /dev/null +++ b/README.md @@ -0,0 +1,330 @@ +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](https://docs.mongodb.com/manual/reference/bson-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. + +# 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: +``` +{ : {: }, ... } +``` +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](https://docs.mongodb.com/manual/reference/operator/) + +# 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"}) +``` +[More SQL vs Mongo comparisons](https://docs.mongodb.com/manual/reference/sql-aggregation-comparison/) + +## 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 } +``` +[More SQL vs Mongo examples](https://docs.mongodb.com/manual/reference/sql-aggregation-comparison/)