My personal notes for MongoDB
Go to file
2021-09-15 12:23:11 -05:00
README.md Relationships 2021-09-15 12:23:11 -05:00

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

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"})

More SQL vs Mongo comparisons

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