Introducción a MongoDB desde Cero

MongoDB es una base de datos NoSQL basada en documentos que utiliza un modelo de datos de tipo JSON, en lugar de filas y columnas tradicionales. Es una base de datos de código abierto, de uso sencillo y diseñada para el desarrollo de aplicaciones modernas y para la nube.

  Características principales

  • Orientada a documentos: Almacena datos en formato JSON/BSON
  • Escalable: Su arquitectura permite añadir más nodos para compartir la carga
  • Flexible: No requiere esquemas fijos como las bases de datos relacionales
  • Alta disponibilidad: Soporte para replicación y tolerancia a errores

BSON (Binary JSON)

MongoDB almacena los datos en documentos BSON, un formato que extiende JSON para incluir tipos de datos adicionales como fechas, enteros binarios y ObjectIds, proporcionando mayor eficiencia en almacenamiento y consulta.

Ejemplo de documento:

json
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "Urian",
  "edad": 30,
  "ciudad": "Bogotá",
  "fecha_registro": ISODate("2024-01-15T10:30:00Z"),
  "activo": true,
  "hobbies": ["programación", "música", "deportes"]
}

Conceptos Fundamentales

NoSQL vs SQL

NoSQL (MongoDB)SQL (MySQL, PostgreSQL)
Documentos JSON/BSONFilas y columnas
Esquema flexibleEsquema fijo
Escalabilidad horizontalEscalabilidad vertical
Consultas con JavaScriptConsultas con SQL

Documentos

Un documento es la unidad básica de datos en MongoDB, similar a una fila en una base de datos relacional, pero mucho más flexible. Cada documento puede tener una estructura diferente.

Ejemplo:

json
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "nombre": "Juan Pérez",
  "email": "juan@email.com",
  "direccion": {
    "calle": "Carrera 15 #85-32",
    "ciudad": "Bogotá",
    "pais": "Colombia"
  }
}

Colecciones

Una colección es un grupo de documentos, similar a una tabla en una base de datos relacional. No requiere esquema fijo.

Ejemplo de colección “usuarios”:

json
// Documento 1
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "nombre": "Juan",
  "edad": 25
}

// Documento 2
{
  "_id": ObjectId("507f1f77bcf86cd799439012"),
  "nombre": "María",
  "email": "maria@email.com",
  "telefono": "3001234567"
}

Clave Principal (_id)

Cada documento tiene un campo _id único que actúa como clave principal. Si no se proporciona, MongoDB lo genera automáticamente como un ObjectId.

Índices

Los índices mejoran significativamente la velocidad de las consultas al crear estructuras de datos optimizadas para búsquedas rápidas.

Operaciones Básicas (CRUD)


Las operaciones CRUD (Create, Read, Update, Delete) son fundamentales en MongoDB. A diferencia de SQL, MongoDB utiliza métodos JavaScript para manipular documentos, ofreciendo mayor flexibilidad y una sintaxis más intuitiva para desarrolladores web.

1CREAR - Insertar Documentos

insertOne() - Insertar un solo documento


Inserta un único documento en una colección. Si no se especifica un _id, MongoDB lo genera automáticamente. Este método es ideal para operaciones individuales y garantiza la integridad de cada inserción.

Sintaxis: db.coleccion.insertOne(documento)

insertMany() - Insertar múltiples documentos


Inserta varios documentos en una sola operación, optimizando el rendimiento al reducir las llamadas a la base de datos. Útil para migraciones o carga masiva de datos. Si un documento falla, puedes configurar si continuar con los demás usando la opción ordered: false.

Sintaxis: db.coleccion.insertMany([documento1, documento2, ...])

javascript
// ✅ Insertar un documento simple
db.usuarios.insertOne({
  "nombre": "Juan Pérez",
  "email": "juan@email.com",
  "edad": 30,
  "ciudad": "Bogotá",
  "fecha_registro": new Date()
})
// Respuesta: { acknowledged: true, insertedId: ObjectId("...") }

// ✅ Insertar múltiples documentos de una sola vez (más eficiente)
db.usuarios.insertMany([
  {
    "nombre": "María García",
    "email": "maria@email.com",
    "edad": 25,
    "ciudad": "Medellín"
  },
  {
    "nombre": "Carlos López",
    "email": "carlos@email.com",
    "edad": 35,
    "ciudad": "Cali"
  }
])
// Respuesta: { acknowledged: true, insertedIds: { '0': ObjectId("..."), '1': ObjectId("...") } }

// ✅ Insertar con _id personalizado
db.usuarios.insertOne({
  "_id": "USER001",
  "nombre": "Admin",
  "email": "admin@email.com",
  "rol": "administrador"
})
2LEER - Consultar Documentos

find() - Buscar múltiples documentos


Recupera todos los documentos que coincidan con los criterios de búsqueda. Retorna un cursor que puede iterarse o convertirse en un array. Permite encadenar métodos como sort(), limit() y skip() para controlar los resultados.

Sintaxis: db.coleccion.find(filtro, proyección)

findOne() - Buscar un solo documento


Recupera el primer documento que coincida con los criterios especificados. Es más eficiente que find() cuando solo necesitas un resultado, ya que detiene la búsqueda al encontrar la primera coincidencia.

Sintaxis: db.coleccion.findOne(filtro, proyección)

Métodos de consulta adicionales

javascript
// ✅ Buscar todos los documentos de la colección
db.usuarios.find()

// ✅ Buscar con un filtro específico
db.usuarios.find({ "ciudad": "Bogotá" })
db.usuarios.find({ "edad": 30 })

// ✅ Buscar con múltiples condiciones (AND implícito)
db.usuarios.find({
  "edad": { $gte: 25 },
  "ciudad": "Bogotá"
})

// ✅ Buscar un solo documento (más rápido)
db.usuarios.findOne({ "email": "juan@email.com" })

// ✅ Proyección: seleccionar solo campos específicos
// 1 = incluir, 0 = excluir
db.usuarios.find({}, { "nombre": 1, "email": 1, "_id": 0 })

// ✅ Ordenar resultados
db.usuarios.find().sort({ "edad": 1 })  // Ascendente (1)
db.usuarios.find().sort({ "edad": -1 }) // Descendente (-1)
db.usuarios.find().sort({ "ciudad": 1, "edad": -1 }) // Múltiples campos

// ✅ Limitar número de resultados
db.usuarios.find().limit(5)

// ✅ Paginación: saltar y limitar documentos
db.usuarios.find().skip(10).limit(5) // Página 3 (si cada página tiene 5 elementos)

// ✅ Encadenar múltiples operaciones
db.usuarios.find({ "edad": { $gte: 18 } })
  .sort({ "nombre": 1 })
  .limit(10)
  .skip(0)

// ✅ Buscar y convertir a array
db.usuarios.find({ "ciudad": "Bogotá" }).toArray()

// ✅ Contar documentos que coinciden con el filtro
db.usuarios.find({ "ciudad": "Bogotá" }).count()

Operadores de Comparación


Los operadores de comparación permiten filtrar documentos basándose en condiciones numéricas o de igualdad (similares a las cláusulas WHERE en SQL).

OperadorSignificadoEjemploResultado
$eqIgual a{ edad: { $eq: 25 } }edad = 25
$neDistinto de{ edad: { $ne: 18 } }edad ≠ 18
$gtMayor que{ precio: { $gt: 100 } }precio > 100
$gteMayor o igual que{ precio: { $gte: 100 } }precio ≥ 100
$ltMenor que{ precio: { $lt: 50 } }precio < 50
$lteMenor o igual que{ precio: { $lte: 50 } }precio ≤ 50
$inCoincide con alguno en un array{ categoria: { $in: ["tecnología", "hogar"] } }categoria ∈ [“tecnología”,“hogar”]
$ninNo coincide con ninguno{ categoria: { $nin: ["ropa", "deporte"] } }categoria ∉ [“ropa”,“deporte”]

Operadores Lógicos


Permiten combinar múltiples condiciones en una sola consulta usando lógica booleana (AND, OR, NOT, NOR).

OperadorDescripciónEjemplo
$andTodas las condiciones deben cumplirse{ $and: [ { precio: { $gt: 100 } }, { stock: { $gte: 5 } } ] }
$orCualquiera de las condiciones puede cumplirse{ $or: [ { categoria: "hogar" }, { categoria: "oficina" } ] }
$notNiega una condición{ precio: { $not: { $gt: 500 } } } → precio ≤ 500
$norNinguna condición debe cumplirse{ $nor: [ { activo: true }, { premium: true } ] }

Operadores de Elementos


Verifican la existencia o el tipo de dato de un campo específico en los documentos.

OperadorDescripciónEjemplo
$existsVerifica si el campo existe{ descuento: { $exists: true } }
$typeFiltra por tipo de dato{ edad: { $type: "int" } }

Operadores para Arrays


Permiten realizar consultas avanzadas sobre campos que contienen arrays, evaluando elementos, tamaño y coincidencias.

OperadorDescripciónEjemplo
$allTodos los valores deben estar en el array{ tags: { $all: ["nuevo", "oferta"] } }
$elemMatchCoincidencia en un elemento del array{ puntuaciones: { $elemMatch: { $gte: 80, $lt: 100 } } }
$sizeTamaño exacto del array{ colores: { $size: 3 } }

Operadores de Evaluación


Evalúan expresiones complejas y patrones de texto usando expresiones regulares o comparaciones entre campos.

OperadorDescripciónEjemplo
$regexCoincidencia con expresión regular{ nombre: { $regex: /^A/i } } → nombres que empiecen con “A”
$exprUsa expresiones dentro de la consulta{ $expr: { $gt: ["$ventas", "$gastos"] } }
javascript
// ✅ Operadores de Comparación
db.usuarios.find({ "edad": { $gt: 25 } })        // Mayor que 25
db.usuarios.find({ "edad": { $gte: 25 } })       // Mayor o igual a 25
db.usuarios.find({ "edad": { $lt: 30 } })        // Menor que 30
db.usuarios.find({ "edad": { $lte: 30 } })       // Menor o igual a 30
db.usuarios.find({ "edad": { $ne: 25 } })        // Diferente de 25
db.usuarios.find({ "edad": { $eq: 25 } })        // Igual a 25
db.usuarios.find({ "ciudad": { $in: ["Bogotá", "Medellín", "Cali"] } })    // Está en el array
db.usuarios.find({ "ciudad": { $nin: ["Bogotá", "Medellín"] } })           // No está en el array

// ✅ Operadores Lógicos
db.usuarios.find({
  $or: [
    { "ciudad": "Bogotá" },
    { "ciudad": "Medellín" }
  ]
})

db.usuarios.find({
  $and: [
    { "edad": { $gte: 25 } },
    { "ciudad": "Bogotá" }
  ]
})

db.usuarios.find({
  $nor: [
    { "activo": false },
    { "bloqueado": true }
  ]
})

// ✅ Operadores para Arrays
db.usuarios.find({ "hobbies": "programación" })  // Contiene el elemento
db.usuarios.find({ "hobbies": { $in: ["música", "deportes"] } })  // Contiene al menos uno
db.usuarios.find({ "hobbies": { $all: ["música", "deportes"] } }) // Contiene todos
db.usuarios.find({ "hobbies": { $size: 3 } })    // Array con exactamente 3 elementos

// ✅ Búsqueda con Expresiones Regulares (Regex)
db.usuarios.find({ "nombre": /Juan/ })                              // Contiene "Juan"
db.usuarios.find({ "nombre": { $regex: "^Juan" } })                 // Empieza con "Juan"
db.usuarios.find({ "nombre": { $regex: "Pérez$" } })                // Termina con "Pérez"
db.usuarios.find({ "nombre": { $regex: "juan", $options: "i" } })   // Case insensitive

// ✅ Operadores de Existencia
db.usuarios.find({ "telefono": { $exists: true } })   // Tiene el campo telefono
db.usuarios.find({ "telefono": { $exists: false } })  // No tiene el campo telefono

// ✅ Operadores de Tipo
db.usuarios.find({ "edad": { $type: "int" } })        // El campo es un entero
db.usuarios.find({ "edad": { $type: "string" } })     // El campo es un string

// ✅ Consultas Complejas Combinadas
db.usuarios.find({
  $and: [
    { "edad": { $gte: 18, $lte: 65 } },
    { "ciudad": { $in: ["Bogotá", "Medellín"] } },
    { "activo": true },
    { "email": { $exists: true } }
  ]
})
3ACTUALIZAR - Modificar Documentos:

updateOne() - Actualizar un documento


Modifica el primer documento que coincida con el filtro especificado. Usa operadores como $set, $inc, $push, $pull para realizar cambios precisos sin reemplazar todo el documento.

Sintaxis: db.coleccion.updateOne(filtro, actualización, opciones)

updateMany() - Actualizar múltiples documentos


Modifica todos los documentos que coincidan con el filtro. Ideal para actualizaciones masivas como cambiar estados, incrementar valores o agregar campos a múltiples registros simultáneamente.

Sintaxis: db.coleccion.updateMany(filtro, actualización, opciones)

replaceOne() - Reemplazar documento completo


Reemplaza completamente un documento por uno nuevo, manteniendo solo el _id original. A diferencia de updateOne(), elimina todos los campos no especificados en el nuevo documento.

Sintaxis: db.coleccion.replaceOne(filtro, nuevoDocumento, opciones)

Operadores de actualización y ejemplos

javascript
// ✅ $set - Actualizar o agregar campos
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $set: { "edad": 31, "ciudad": "Medellín", "activo": true } }
)

// ✅ updateMany - Actualizar múltiples documentos
db.usuarios.updateMany(
  { "ciudad": "Bogotá" },
  { $set: { "pais": "Colombia", "zona": "Andina" } }
)

// ✅ $inc - Incrementar o decrementar valores numéricos
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $inc: { "edad": 1, "puntos": 10 } }  // edad +1, puntos +10
)

db.productos.updateOne(
  { "_id": "PROD001" },
  { $inc: { "stock": -5 } }  // Restar 5 del stock
)

// ✅ $push - Agregar elementos a un array
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $push: { "hobbies": "lectura" } }
)

// ✅ $push con $each - Agregar múltiples elementos
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $push: { "hobbies": { $each: ["fotografía", "cocina"] } } }
)

// ✅ $pull - Remover elementos de un array
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $pull: { "hobbies": "música" } }
)

// ✅ $unset - Eliminar campos del documento
db.usuarios.updateOne(
  { "email": "juan@email.com" },
  { $unset: { "telefono": "", "direccion": "" } }
)

// ✅ $rename - Renombrar campos
db.usuarios.updateMany(
  {},
  { $rename: { "nombre": "nombre_completo" } }
)

// ✅ $mul - Multiplicar valor de un campo
db.productos.updateOne(
  { "_id": "PROD001" },
  { $mul: { "precio": 1.15 } }  // Aumentar precio 15%
)

// ✅ $min y $max - Actualizar solo si es menor/mayor
db.estadisticas.updateOne(
  { "usuario_id": "USER001" },
  { 
    $min: { "puntuacion_minima": 50 },  // Solo actualiza si 50 es menor
    $max: { "puntuacion_maxima": 100 }  // Solo actualiza si 100 es mayor
  }
)

// ✅ replaceOne - Reemplazar documento completo (mantiene solo _id)
db.usuarios.replaceOne(
  { "email": "juan@email.com" },
  {
    "nombre": "Juan Carlos Pérez",
    "email": "juan@email.com",
    "edad": 31,
    "ciudad": "Medellín",
    "profesion": "Desarrollador"
  }
)

// ✅ upsert - Actualizar o insertar si no existe
db.usuarios.updateOne(
  { "email": "nuevo@email.com" },
  { $set: { "nombre": "Usuario Nuevo", "edad": 25 } },
  { upsert: true }  // Crea el documento si no existe
)

// ✅ Actualización compleja combinada
db.usuarios.updateOne(
  { "_id": ObjectId("507f1f77bcf86cd799439011") },
  {
    $set: { "ultimo_acceso": new Date(), "activo": true },
    $inc: { "numero_accesos": 1 },
    $push: { "historial": { fecha: new Date(), accion: "login" } }
  }
)
4ELIMINAR - Borrar Documentos:

deleteOne() - Eliminar un documento


Elimina el primer documento que coincida con el filtro especificado. Útil cuando necesitas eliminar un registro específico identificado por un criterio único.

Sintaxis: db.coleccion.deleteOne(filtro)

deleteMany() - Eliminar múltiples documentos


Elimina todos los documentos que coincidan con el filtro. Ideal para limpieza masiva de datos, eliminación de registros obsoletos o depuración. ⚠️ Usa con precaución.

Sintaxis: db.coleccion.deleteMany(filtro)

drop() - Eliminar colección completa


Elimina completamente una colección incluyendo todos sus documentos e índices. Esta operación es irreversible y libera el espacio de almacenamiento.

Sintaxis: db.coleccion.drop()

Ejemplos de operaciones de eliminación

javascript
// ✅ Eliminar un documento específico
db.usuarios.deleteOne({ "email": "juan@email.com" })
// Respuesta: { acknowledged: true, deletedCount: 1 }

// ✅ Eliminar por _id (más eficiente)
db.usuarios.deleteOne({ "_id": ObjectId("507f1f77bcf86cd799439011") })

// ✅ Eliminar múltiples documentos que cumplan una condición
db.usuarios.deleteMany({ "ciudad": "Bogotá" })
db.usuarios.deleteMany({ "activo": false })
db.usuarios.deleteMany({ "fecha_registro": { $lt: new Date("2020-01-01") } })

// ⚠️ PELIGRO: Eliminar TODOS los documentos de una colección
db.usuarios.deleteMany({})  // Esto borra todo pero mantiene la colección y los índices

// ✅ Eliminar documentos con condiciones complejas
db.usuarios.deleteMany({
  $and: [
    { "ultimo_acceso": { $lt: new Date("2023-01-01") } },
    { "activo": false }
  ]
})

// ✅ Eliminar colección completa (incluye índices)
db.usuarios.drop()
// Respuesta: true (si se eliminó correctamente)

// ✅ Eliminar base de datos completa
db.dropDatabase()

// ✅ Verificar qué se eliminaría antes de borrar (buena práctica)
db.usuarios.find({ "activo": false }).count()  // Ver cuántos serían eliminados
db.usuarios.deleteMany({ "activo": false })    // Luego eliminarlos
5OPERACIONES AVANZADAS:

Agregación - aggregate()


El framework de agregación procesa y transforma datos mediante un pipeline (tubería) de operaciones secuenciales. Cada etapa transforma los documentos y los pasa a la siguiente, permitiendo realizar cálculos complejos, agrupaciones, filtrados y transformaciones de datos.

Operadores comunes:

  • $match: Filtra documentos (similar a WHERE en SQL)
  • $group: Agrupa documentos y realiza operaciones de agregación (similar a GROUP BY)
  • $sort: Ordena los resultados
  • $project: Selecciona qué campos mostrar
  • $limit: Limita el número de documentos
  • $sum, $avg, $min, $max: Operaciones matemáticas

Sintaxis: db.coleccion.aggregate([etapa1, etapa2, ...])

countDocuments() - Contar documentos


Cuenta el número de documentos que coinciden con un filtro específico. Más preciso que el método count() obsoleto, ya que cuenta los documentos reales en la colección.

Sintaxis: db.coleccion.countDocuments(filtro)

javascript
// ✅ Contar documentos con filtro
db.usuarios.countDocuments({ "ciudad": "Bogotá" })
db.usuarios.countDocuments({ "edad": { $gte: 18 } })
db.usuarios.countDocuments({})  // Contar todos los documentos

// ✅ Agrupación básica con operadores de agregación
db.usuarios.aggregate([
  {
    $group: {
      "_id": "$ciudad",                    // Agrupar por ciudad
      "total": { $sum: 1 },                // Contar documentos
      "promedio_edad": { $avg: "$edad" },  // Promedio de edad
      "edad_maxima": { $max: "$edad" },    // Edad máxima
      "edad_minima": { $min: "$edad" }     // Edad mínima
    }
  }
])

// ✅ Pipeline de agregación completo
db.usuarios.aggregate([
  // Etapa 1: Filtrar documentos
  { $match: { "edad": { $gte: 25 }, "activo": true } },
  
  // Etapa 2: Agrupar y calcular estadísticas
  { 
    $group: {
      "_id": "$ciudad",
      "total_usuarios": { $sum: 1 },
      "promedio_edad": { $avg: "$edad" },
      "emails": { $push: "$email" }  // Crear array con todos los emails
    }
  },
  
  // Etapa 3: Ordenar resultados
  { $sort: { "total_usuarios": -1 } },
  
  // Etapa 4: Limitar resultados
  { $limit: 10 }
])

// ✅ Agregación con $project (seleccionar campos)
db.usuarios.aggregate([
  {
    $project: {
      "nombre": 1,
      "email": 1,
      "edad": 1,
      "es_mayor": { $gte: ["$edad", 18] },  // Campo calculado
      "nombre_mayuscula": { $toUpper: "$nombre" }
    }
  }
])

// ✅ Agregación con $lookup (JOIN entre colecciones)
db.pedidos.aggregate([
  {
    $lookup: {
      from: "usuarios",           // Colección a unir
      localField: "usuario_id",   // Campo en pedidos
      foreignField: "_id",        // Campo en usuarios
      as: "usuario_info"          // Nombre del array resultante
    }
  }
])

// ✅ Agregación compleja: análisis de ventas
db.ventas.aggregate([
  // Filtrar ventas del último año
  { $match: { "fecha": { $gte: new Date("2024-01-01") } } },
  
  // Agrupar por producto y calcular totales
  {
    $group: {
      "_id": "$producto_id",
      "total_ventas": { $sum: "$cantidad" },
      "ingreso_total": { $sum: { $multiply: ["$precio", "$cantidad"] } },
      "venta_promedio": { $avg: "$cantidad" }
    }
  },
  
  // Ordenar por ingresos (de mayor a menor)
  { $sort: { "ingreso_total": -1 } },
  
  // Tomar los top 5 productos
  { $limit: 5 },
  
  // Formatear resultado final
  {
    $project: {
      "producto_id": "$_id",
      "total_ventas": 1,
      "ingreso_total": { $round: ["$ingreso_total", 2] },
      "venta_promedio": { $round: ["$venta_promedio", 2] },
      "_id": 0
    }
  }
])

// ✅ Agregación con $unwind (descomponer arrays)
db.usuarios.aggregate([
  { $unwind: "$hobbies" },  // Crear un documento por cada hobby
  { $group: { "_id": "$hobbies", "total": { $sum: 1 } } },  // Contar por hobby
  { $sort: { "total": -1 } }
])

// ✅ distinct() - Obtener valores únicos de un campo
db.usuarios.distinct("ciudad")  // ["Bogotá", "Medellín", "Cali", ...]
db.productos.distinct("categoria")

Índices - Optimización de Consultas


Los índices son estructuras de datos especiales que mejoran drásticamente la velocidad de las consultas al crear una tabla de búsqueda ordenada. Sin índices, MongoDB debe escanear cada documento (collection scan); con índices, puede saltar directamente a los datos relevantes.

  Tipos de índices

  • Índice simple: En un solo campo
  • Índice compuesto: En múltiples campos
  • Índice de texto: Para búsquedas de texto completo
  • Índice único: Garantiza valores únicos
  • Índice TTL: Elimina documentos automáticamente después de cierto tiempo

  Sintaxis

  • createIndex(campos, opciones): Crea un nuevo índice
  • getIndexes(): Lista todos los índices
  • dropIndex(campos): Elimina un índice

javascript
// ✅ Crear índice simple (1 = ascendente, -1 = descendente)
db.usuarios.createIndex({ "email": 1 })
db.usuarios.createIndex({ "edad": 1 })

// ✅ Crear índice único (no permite valores duplicados)
db.usuarios.createIndex({ "email": 1 }, { unique: true })
db.usuarios.createIndex({ "username": 1 }, { unique: true })

// ✅ Crear índice compuesto (múltiples campos)
// Útil para consultas que filtran por ambos campos
db.usuarios.createIndex({ "ciudad": 1, "edad": 1 })
db.productos.createIndex({ "categoria": 1, "precio": -1 })

// ✅ Crear índice de texto (búsquedas de texto completo)
db.usuarios.createIndex({ "nombre": "text", "biografia": "text" })
db.articulos.createIndex({ "titulo": "text", "contenido": "text" })

// Luego buscar con:
db.usuarios.find({ $text: { $search: "Juan Pérez" } })

// ✅ Crear índice TTL (Time To Live) - elimina documentos automáticamente
// Elimina documentos 30 días después de la fecha especificada
db.sesiones.createIndex(
  { "fecha_expiracion": 1 }, 
  { expireAfterSeconds: 2592000 }  // 30 días = 2,592,000 segundos
)

// ✅ Crear índice parcial (solo indexa documentos que cumplan condición)
db.usuarios.createIndex(
  { "email": 1 },
  { partialFilterExpression: { "activo": true } }
)

// ✅ Crear índice sparse (no indexa documentos sin el campo)
db.usuarios.createIndex(
  { "telefono": 1 },
  { sparse: true }
)

// ✅ Ver todos los índices de una colección
db.usuarios.getIndexes()

// ✅ Ver estadísticas de uso de índices
db.usuarios.aggregate([{ $indexStats: {} }])

// ✅ Eliminar un índice específico
db.usuarios.dropIndex({ "email": 1 })
db.usuarios.dropIndex("email_1")  // Por nombre

// ✅ Eliminar todos los índices (excepto _id)
db.usuarios.dropIndexes()

// ✅ Analizar el plan de ejecución de una consulta
db.usuarios.find({ "email": "juan@email.com" }).explain("executionStats")
// Muestra si usa índice, cuántos documentos examinó, tiempo, etc.

// ✅ Crear índice en segundo plano (no bloquea la colección)
db.usuarios.createIndex(
  { "fecha_registro": 1 },
  { background: true }
)

// ✅ Índice geoespacial (para coordenadas y ubicaciones)
db.lugares.createIndex({ "ubicacion": "2dsphere" })

// Luego buscar lugares cercanos:
db.lugares.find({
  ubicacion: {
    $near: {
      $geometry: { type: "Point", coordinates: [-74.0721, 4.7110] },  // Bogotá
      $maxDistance: 5000  // 5km
    }
  }
})

// ✅ Verificar si una colección tiene índices
db.usuarios.getIndexes().length > 1  // true si hay más que el _id
  Ventajas de MongoDB

Flexibilidad de Esquema

  • Sin esquema fijo: documentos con estructuras distintas
  • Ágil: cambios sin migraciones complejas
  • JSON nativo: integración natural con apps modernas

Alto Rendimiento

  • Índices: búsquedas rápidas
  • Consultas avanzadas: operadores y regex
  • Caché automático: acelera lecturas frecuentes

Ecosistema Rico

  • Drivers: Node.js, Python, Java, Go, PHP, C#
  • Herramientas: Compass, Atlas, mongosh
  • Integración: Express.js, Django, Spring Boot

Alta Disponibilidad

  • Replicación: copias en varios nodos
  • Tolerancia a fallos: servicio continuo
  • Backups: automáticos y recuperables

Escalabilidad

  • Sharding: distribuye datos en servidores
  • Balanceo: reparte carga de consultas
  • Crecimiento elástico: agrega nodos según demanda