MongoDB es una base de datos NoSQL orientada a documentos: en vez de tablas con filas fijas, guarda JSON (técnicamente BSON) con una estructura flexible, lo que la hace cómoda cuando tus datos no calzan bien en un esquema relacional rígido o cambian seguido. Esta es una guía de referencia con conexión, operaciones CRUD, relaciones entre colecciones, importación de CSV, operadores de consulta, proyecciones y el framework de agregación, con ejemplos reales de mongosh (si corres MongoDB en Docker, el post de comandos esenciales de Docker te sirve para levantar el contenedor).

Conectarse a MongoDB y crear una base de datos y colección

mongosh "mongodb://127.0.0.1:27017" --username user --authenticationDatabase admin
mongosh --host mongodb0.example.com --port 28015

Crear (o cambiar a) una base de datos con use, listar las bases con show dbs y crear una colección simplemente referenciándola:

test> use mibase
mibase> show dbs
admin 100.00 KiB
config 108.00 KiB
local 76.00 KiB

// crear una colección
mibase> db.persona
mibase.persona

// listar las colecciones
mibase> show collections

Insertar documentos

insertOne guarda un solo documento, insertMany guarda varios:

mibase> db.persona.insertOne({"nombres":"Maricel","apellidos":"casanova","edad":25,"sexo":"femenino"})

mibase> db.persona.insertMany([
  {"nombres":"Max","apellidos":"casanova","edad":39},
  {"nombres":"llasna","apellidos":"gomez","edad":31}
])

mibase> db.plaza.insertOne({
  nombre: "plaza2",
  precioPantalones: [
    { nombre: "tienda2", valormenor: 100, valormayor: 1000 },
    { nombre: "tienda3", valormenor: 300, valormayor: 2000 }
  ]
})

mibase> db.plaza.find().pretty()
[
  {
    _id: ObjectId("64e0065bc68bd53aaff8c599"),
    nombre: 'plaza2',
    precioPantalones: [
      { nombre: 'tienda2', valormenor: 100, valormayor: 1000 },
      { nombre: 'tienda3', valormenor: 300, valormayor: 2000 }
    ]
  }
]

Otro ejemplo, insertando una película con un arreglo de actores:

mibase> db.peliculas.insertOne({titulo:"el pirata", ano:2021, actores:["max","juan","jose","macarena","isabel"]})

mibase> db.peliculas.find().pretty()
[
  {
    _id: ObjectId("64e39d5bc68bd53aaff8c5a3"),
    titulo: 'el pirata',
    ano: 2021,
    actores: [ 'max', 'juan', 'jose', 'macarena', 'isabel' ]
  }
]

mibase> db.peliculas.insertMany([
  {titulo:"hola a todos", ano:1999, actores:["coke","juan"]},
  {titulo:"pedrito el lobo", ano:2023, actores:["davis","guillermo",{dato1:"hola",dato2:"chao"}]}
])

insert() también existe (forma antigua, equivalente a insertOne/insertMany según el argumento):

mibase> db.peliculas.insert([{titulo:"peliculas 1", ano:2000},{titulo:"pelicula2", ano:1000}])

Insert ordenado (ordered)

Con {ordered: true}, si un documento falla (por ejemplo por _id duplicado), la operación se detiene y se reporta el error en detalle:

mibase> db.peliculas.insert(
  [
    {_id: ObjectId("64e39f8fc68bd53aaff8c5a7"), titulo:"prueba 2", ano:2002},
    {titulo:"el conquistador", ano:2222}
  ],
  {ordered: true}
)

Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: mibase.peliculas index: _id_ dup key: { _id: ObjectId('64e39f8fc68bd53aaff8c5a7') }
Result: BulkWriteResult {
  insertedCount: 0,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: {
    '0': ObjectId("64e39f8fc68bd53aaff8c5a7"),
    '1': ObjectId("64e3a56fc68bd53aaff8c5a8")
  }
}
Write Errors: [
  WriteError {
    err: {
      index: 0,
      code: 11000,
      errmsg: "E11000 duplicate key error collection: mibase.peliculas index: _id_ dup key: { _id: ObjectId('64e39f8fc68bd53aaff8c5a7') }",
      op: { _id: ObjectId("64e39f8fc68bd53aaff8c5a7"), titulo: 'prueba 2', ano: 2002 }
    }
  }
]

Consultas con find y findOne

// mostrar todos los documentos
mibase> db.persona.find()

// mostrar el resultado pero sin el campo _id
mibase> db.persona.find({"edad":25},{"_id":0})

// sin _id ni edad
mibase> db.persona.find({"edad":25},{"_id":0,"edad":0})

// solo el campo "nombres"
mibase> db.persona.find({"sexo":"femenino"},{"nombres":1,"_id":0})

// buscar por _id
mibase> db.persona.find({"_id":ObjectId("64a642bcb7ce53bbb5c28018")})

Cursor:

mibase> db.persona.find().count()
mibase> db.persona.find().limit(3)

Filtrar por tipo de dato:

mibase> db.persona.find({"edad":{$type:"int"}})
mibase> db.persona.find({"nombres":{$type:"string"}})

findOne, y encadenar con una propiedad del resultado:

mibase> db.address.insertOne({"patron_id":"one","street":"serrano 266","city":"santiago","country":"chile"})

mibase> db.address.findOne({patron_id:"one"}).street
serrano 266

mibase> db.persona.findOne({edad:39})
{
  _id: ObjectId("64a6351fb7ce53bbb5c28014"),
  nombres: 'Kim',
  apellidos: 'foxterry',
  edad: 39
}

Guardar un resultado en una variable y reutilizarlo:

mibase> db.patron.findOne({"nombre":"Maximiliano Casanova"})._id
one

mibase> var varAuxiliar = db.patron.findOne({"nombre":"Maximiliano Casanova"})._id
mibase> varAuxiliar
one

mibase> db.address.find({patron_id: varAuxiliar})
[
  { _id: ObjectId("64dfa504c68bd53aaff8c595"), patron_id: 'one', street: 'serrano 266', city: 'santiago', country: 'chile' }
]

// o directamente anidado, sin variable intermedia
mibase> db.address.find({patron_id: db.patron.findOne({"nombre":"Maximiliano Casanova"})._id})

mibase> db.address.findOne({patron_id: db.patron.findOne({"nombre":"Maximiliano Casanova"})._id}).city
santiago

// con proyección
mibase> db.address.findOne(
  {patron_id: db.patron.findOne({"nombre":"Maximiliano Casanova"})._id},
  {city:1, country:1}
)
{ _id: ObjectId("64dfa504c68bd53aaff8c595"), city: 'santiago', country: 'chile' }

Con operadores

Ver la referencia de operadores de MongoDB o la guía de W3Schools.

mibase> db.persona.find({edad:{$gt:39}})
mibase> db.persona.findOne({edad:{$eq:39}})
mibase> db.persona.find({edad:{$lt:39}})
mibase> db.persona.find({edad:{$lte:39}})

Actualizar y reemplazar documentos

replaceOne sustituye el documento completo:

mibase> db.persona.replaceOne(
  {"_id":ObjectId("64a642bcb7ce53bbb5c28018")},
  {"edad":26,"nombres":"Antonia"}
)

upsert: si {upsert:true}, inserta el documento si no existe; con {upsert:false} (el valor por defecto) no lo inserta:

mibase> db.persona.replaceOne(
  {"_id":ObjectId("64a642bcb7ce53bbb5c28018")},
  {"edad":26,"nombres":"Antonias","apellido":"Garrido"},
  {upsert:false}
)

update / updateOne / updateMany con $set:

// busca por {"nombres":"Kim"} y aplica $set
mibase> db.persona.updateOne({"nombres":"Kim"},{$set:{"apellidos":"perrito","edad":3}},{upsert:true})

// actualizar varios documentos con multi:true
mibase> db.persona.update({"edad":1},{$set:{"apellidos":"canes","edad":39}},{multi:true})
mibase> db.persona.updateMany({"edad":39},{$set:{"apellidos":"foxterry","edad":39}},{multi:true})

Ejemplo agregando un sub-documento address a un cliente:

mibase> db.patron.find()
[ { _id: 'one', nombre: 'Maximiliano Casanova' } ]

mibase> db.patron.updateOne(
  {_id:"one"},
  {$set:{"address":{"street":"serrano 266","city":"santiago","country":"Chile","depto":"715"}}},
  {upsert:true}
)

mibase> db.patron.find()
[
  {
    _id: 'one',
    nombre: 'Maximiliano Casanova',
    address: { street: 'serrano 266', city: 'santiago', country: 'Chile', depto: '715' }
  }
]

Operadores de actualización ($set, $inc, $min, $max, $mul, $unset, $rename):

mibase> db.peliculas.updateOne({titulo:"actor4"},{$set:{ano:9999}})

mibase> db.peliculas.updateOne({actores:{$in:["juan","coke"]}},{$set:{ano:1010}})
mibase> db.peliculas.updateMany({actores:{$in:["juan","coke"]}},{$set:{ano:101110}})

// $inc suma al valor actual
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$inc:{ano:1}})

// $min solo actualiza si el nuevo valor es menor al actual
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$min:{ano:1}})

// $max solo actualiza si el nuevo valor es mayor al actual
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$max:{ano:2}})

// $mul multiplica el valor actual
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$mul:{ano:2}})

// $unset elimina un campo
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$unset:{"ano":""}})

// $rename cambia el nombre de un campo
mibase> db.peliculas.updateOne({actores:{$in:["coke"]}},{$rename:{"actores":"actores2"}})

Documentos embebidos en arreglos

Cuando un campo contiene un arreglo de sub-documentos:

// estructura de ejemplo
{
  _id: 1,
  almacen: "almacen1",
  inventario: [
    {producto:"productoA", in_stock:101},
    {producto:"productoB", in_stock:10},
    {producto:"productoC", in_stock:30}
  ]
}

mibase> db.producto.insertMany([{
  "item":"prodcutoA",
  "stock":[{"seccion":"A","almacen":200},{"seccion":"B","almacen":200},{"seccion":"A","Bodega":1000}]
}])

mibase> db.producto.find()
[
  {
    _id: ObjectId("64d0471b656e5fd5243faa00"),
    item: 'prodcutoA',
    stock: [
      { seccion: 'A', almacen: 200 },
      { seccion: 'B', almacen: 200 },
      { seccion: 'A', Bodega: 1000 }
    ]
  }
]

Buscar dentro del arreglo por un campo del sub-documento, o por posición:

mibase> db.producto.find({"stock.seccion":"A"})
mibase> db.producto.find({"stock.0.seccion":"A"})

Eliminar documentos, colecciones y bases de datos

db.miColeccion.drop()     // elimina todos los documentos de la colección (y la colección misma)
db.dropDatabase()         // elimina la base de datos actual

Tipos de datos en MongoDB

Tipo Alias
Double double
String string
Object object
Array array
Binary Data binData
Undefined (deprecado) undefined
ObjectId objectid
Boolean bool
Date date
Null null
Regular Expression regex
DBPointer (deprecado) dbPointer
JavaScript javascript
Symbol (deprecado) symbol
JavaScript con scope (deprecado) javascriptWithScope
Entero de 32 bits int
Timestamp timestamp
Entero de 64 bits long
Decimal128 decimal
Min Key minKey
Max Key maxKey

Relaciones 1 a 1, 1 a N y N a N

1 a N (una plaza con varios locales, referenciados por id_plaza):

mibase> db.plaza.insertOne({nombre:"plaza1"})
mibase> db.plaza.find().pretty()
[ { _id: ObjectId("64dfffadc68bd53aaff8c597"), nombre: 'plaza1' } ]

mibase> db.pantalon.insertOne({
  nombretienda:"tienda1", valorminimo:100, valormaximo:1000,
  id_plaza: ObjectId("64dfffadc68bd53aaff8c597")
})

mibase> db.pantalon.insertMany([
  {nombre:"tienda2", precio:3000, id_plaza:ObjectId("64e0065bc68bd53aaff8c599")},
  {nombre:"tienda3", precio:4500, id_plaza:ObjectId("64e0065bc68bd53aaff8c599")},
  {nombre:"tienda4", precio:1200, id_plaza:ObjectId("64e0065bc68bd53aaff8c599")}
])

mibase> db.pantalon.find()

N a N (tiendas y empleados, cada uno referenciando al otro):

mibase> db.tienda.insertMany([
  {nombre:"tienda1", direccion:"serrano 266"},
  {nombre:"tienda2", direccion:"llano alto 123"}
])

mibase> db.empleado.insertMany([
  {nombre:"Max", tienda:[ObjectId("64e0103bc68bd53aaff8c59d"),ObjectId("64e0103bc68bd53aaff8c59e")]},
  {nombre:"vale", tienda:[ObjectId("64e0103bc68bd53aaff8c59e")]}
])

mibase> db.empleado.find()

mibase> db.tienda.insertMany([
  {nombre:"tienda1", empleado:[ObjectId("64e015c1c68bd53aaff8c59f"),ObjectId("64e015c1c68bd53aaff8c5a0")]},
  {nombre:"tienda2", empleado:[ObjectId("64e015c1c68bd53aaff8c5a0")]}
])

Importar un archivo CSV a una colección

Si tu MongoDB corre dentro de un contenedor Docker, el archivo CSV tiene que existir dentro del contenedor antes de poder importarlo — por eso el primer paso es copiarlo con docker cp. Si corres MongoDB directo en tu máquina, puedes saltarte esos dos pasos y ejecutar mongoimport directamente.

Crear el archivo CSV:

titulo,autor,publicacion
"el lobo solitario","maximiliano casanova","2000/02/02"
"papelucho","valeria gome","1989/10/12"

Copiar el archivo dentro del contenedor de MongoDB:

docker cp libro.csv mongodb:/home/compartir

Entrar al contenedor:

docker exec -it mongodb bash

Importar el archivo con mongoimport:

root@54cded7c9e8a:/# mongoimport --db mibase --collection libros --type csv --headerline \
  --file libro.csv --username user --authenticationDatabase admin

2023-08-21T19:15:15.386+0000 connected to: mongodb://localhost/
2023-08-21T19:15:15.479+0000 2 document(s) imported successfully. 0 document(s) failed to import.

Y verificar en mongosh:

mibase> db.libros.find()
[
  { _id: ObjectId("64e3b7c3deb40b27a4575685"), titulo: 'papelucho', autor: 'valeria gome', publicacion: '1989/10/12' },
  { _id: ObjectId("64e3b7c3deb40b27a4575686"), titulo: 'el lobo solitario', autor: 'maximiliano casanova', publicacion: '2000/02/02' }
]

Operadores de comparación y lógicos

mibase> db.persona.find({edad:{$gt:39}})
mibase> db.persona.findOne({edad:{$eq:39}})
mibase> db.persona.find({edad:{$lt:39}})
mibase> db.persona.find({edad:{$lte:39}})
mibase> db.persona.find({"edad":{$in:[39,40,43]}})
mibase> db.producto.find({"stock.almacen":{$in:[200,300]}})
mibase> db.persona.find({"edad":{$nin:[39]}})

mibase> db.peliculas.find({$and:[{"ano":{$gte:1999}},{ano:{$lte:2000}}]})
mibase> db.peliculas.find({$or:[{"ano":{$gte:2000}},{ano:2023}]})
mibase> db.peliculas.find({ano:{$not:{$gte:2021}}})
mibase> db.peliculas.find({$nor:[{ano:{$gte:2021}}]})

mibase> db.peliculas.find({actores:{$exists:true}})
mibase> db.peliculas.find({actores:{$exists:false}})
mibase> db.peliculas.find({actores:{$type:"string"}})

Comparación: $eq (igual), $ne (distinto), $gt (mayor), $gte (mayor o igual), $lt (menor), $lte (menor o igual), $in (dentro de un arreglo).

Lógicos: $and, $or, $nor (ninguna coincide), $not (niega la condición).

Evaluación: $regex (expresiones regulares), $text (búsqueda de texto), $where (expresión JavaScript).

Operadores regex, size, all y elemMatch

// expresión regular
mibase> db.peliculas.find({titulo:{$regex:/pelicula/}})

// cantidad exacta de elementos en el arreglo
mibase> db.peliculas.find({"actores":{$size:5}})
mibase> db.peliculas.find({"actores":{$size:2}})

// el arreglo debe contener todos los valores indicados
mibase> db.peliculas.find({"actores":{$all:["juan"]}})

// al menos un elemento del arreglo cumple todas las condiciones
mibase> db.peliculas.find({actores:{$elemMatch:{edad:{$gt:20}}}})

Cursores: sort, skip, limit y next

// guardar el cursor en una variable y recorrerlo manualmente
mibase> const mivar = db.peliculas.find()
mibase> mivar.next()
mibase> mivar.next()

// ordenar ascendente / descendente
mibase> db.peliculas.find().sort({ano:1})
mibase> db.peliculas.find().sort({ano:-1,titulo:1})

// limitar y paginar resultados
mibase> db.peliculas.find().sort({"ano":-1}).limit(2)
mibase> db.peliculas.find().sort({"ano":-1}).limit(2).skip(1)

Proyecciones

mibase> db.persona.find({"edad":25},{"_id":0,"edad":0})
mibase> db.persona.find({"sexo":"femenino"},{"nombres":1,"_id":0})

Proyecciones con matrices ($, $slice)

// el operador $ proyecta solo el elemento del arreglo que hizo match
mibase> db.peliculas.find({actores:"davis"},{"actores.$":1})
[ { _id: ObjectId("64e39ea0c68bd53aaff8c5a5"), actores: [ 'davis' ] } ]

// $slice limita cuántos elementos del arreglo se devuelven
mibase> db.peliculas.find({},{actores:{$slice:2}})
mibase> db.peliculas.find({},{actores:{$slice:1}})

// $slice con [skip, limit]
mibase> db.peliculas.find({},{actores:{$slice:[1,2]},ano:1})

deleteOne, deleteMany y drop

mibase> db.peliculas.deleteOne({actores:{$in:["coke"]}})
{ acknowledged: true, deletedCount: 0 }

mibase> db.peliculas.deleteMany({actores2:{$in:["coke"]}})
{ acknowledged: true, deletedCount: 1 }

// eliminar todos los documentos de la colección
mibase> db.peliculas.deleteMany()

// eliminar la colección completa
mibase> db.peliculas.drop()

// eliminar toda la base de datos
mibase> use mibase
mibase> db.dropDatabase()

Framework de agregación

mibase> db.proyecto.aggregate([
  { $match: { no_cdtos: { $gte: 352 } } }
])

Agrupar y sumar un campo por sucursal:

mibase> db.proyecto.aggregate([
  { $match: { B_adeudo: "Con adeudo" } },
  { $group: { _id: { id_sucursal: "$id_sucursal" }, clienteAdeudo: { $sum: "$no_clientes" } } }
])

Agregar un $sort para ordenar el resultado agrupado:

mibase> db.proyecto.aggregate([
  { $match: { B_adeudo: "Con adeudo" } },
  { $group: { _id: { id_sucursal: "$id_sucursal" }, clienteAdeudo: { $sum: "$no_clientes" } } },
  { $sort: { "clienteAdeudo": -1 } }
])

Y con $project para quedarte solo con ciertos campos, o para calcular un campo nuevo con $concat:

mibase> db.proyecto.aggregate([
  { $match: { B_adeudo: "Con adeudo" } },
  { $group: { _id: { id_sucursal: "$id_sucursal" }, clienteAdeudo: { $sum: "$no_clientes" } } },
  { $sort: { "clienteAdeudo": -1 } },
  { $project: { _id: 0 } }
])

mibase> db.proyecto.aggregate([
  { $match: { B_adeudo: "Con adeudo" } },
  { $group: { _id: { id_sucursal: "$id_sucursal" }, clienteAdeudo: { $sum: "$no_clientes" } } },
  { $sort: { "clienteAdeudo": -1 } },
  {
    $project: {
      _id: 1,
      camponuevo: { $concat: ["es un campo ", "nuevo para informar"] }
    }
  }
])

Con esto cubres las operaciones más comunes de MongoDB: conexión, CRUD completo, relaciones entre colecciones, importación de datos, operadores de consulta, proyecciones y agregación.