🍃 2.9 · MongoDB y Mongoose: la base de datos NoSQL más popular

⏱ 5h 00min ⚡ 80 XP 🏅 Profesional Junior 📖 Backend FullStack
"No todo dato es una tabla. Cuando la flexibilidad importa, MongoDB es tu aliado."

🎯 Objetivo del tema

Al terminar este tema serás capaz de: Al terminar este tema serás capaz de explicar la diferencia entre SQL y NoSQL, modelar datos en documentos JSON con MongoDB, conectarte desde Node.js con el ODM Mongoose, y crear schemas con validación. Es la base del stack MERN (MongoDB, Express, React, Node) que domina el mercado.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

🗺️ Mapa del tema

En los Temas 2.4 y 2.8 aprendiste bases de datos RELACIONALES: MySQL y PostgreSQL, donde los datos viven en tablas con esquemas fijos. Hoy conocerás el paradigma OPUESTO: MongoDB, donde los datos viven en documentos JSON flexibles, sin esquema fijo. Cada una tiene su lugar: SQL para datos estructurados y consistentes, NoSQL para datos flexibles, semi-estructurados, o de alto volumen.

1. Qué es NoSQL y cuándo usarlo

El paradigma opuesto a SQL: documentos, no tablas.

2. MongoDB: documentos JSON, no tablas

BSON, colecciones, _id, embebido vs referenciado.

3. Mongoose: el ODM para Node.js

Schemas, modelos, validación, y queries modernas.

4. CRUD con Mongoose: find, save, update, delete

Las 4 operaciones en sintaxis moderna.

5. Modelado: documentos embebidos vs referencias

La decisión más importante en MongoDB.

6. MongoDB Atlas: la BD en la nube gratis

Cómo desplegar tu BD MongoDB en internet sin instalar nada.

2.9.1 Qué es NoSQL y cuándo usarlo

NoSQL (Not Only SQL) es un paraguas para bases de datos que NO usan el modelo relacional de tablas. Hay 4 tipos principales: documentos (MongoDB), clave-valor (Redis), columnar (Cassandra), y grafos (Neo4j). Cada una resuelve un problema distinto. La más popular y versátil es MongoDB: almacena documentos JSON flexibles, ideales para datos semi-estructurados.

📷 Imagen referencial: Comparación: tabla SQL (filas y columnas) vs documento MongoDB (JSON flexible con campos anidados y arrays).
AspectoSQL (PostgreSQL, MySQL)NoSQL (MongoDB)
Modelo de datosTablas con filas y columnas.Documentos JSON flexibles.
EsquemaFijo: defines columnas al crear la tabla.Flexible: cada documento puede tener campos distintos.
RelacionesForeign keys, JOINs.Embebido (subdocumentos) o referencias (manual).
EscalabilidadVertical (más CPU/RAM).Horizontal (más servidores).
TransaccionesACID completas.Solo multi-documento desde MongoDB 4.0.
Cuándo usarloDatos estructurados, transacciones críticas.Datos flexibles, alto volumen, esquemas cambiantes.
⭐ NoSQL != mejor, solo diferente: NoSQL NO reemplaza a SQL. Son herramientas DIFERENTES para problemas DIFERENTES. SQL es mejor para: bancos, sistemas de inventario, cualquier cosa con transacciones críticas y datos estructurados. NoSQL es mejor para: redes sociales, catálogos de productos con atributos variables, logs, IoT, datos semi-estructurados. Si tu proyecto tiene transacciones críticas (no puedes perder datos), USA SQL. Si tu esquema cambia constantemente, USA NoSQL.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.9.2 MongoDB: documentos JSON, no tablas

MongoDB almacena datos en DOCUMENTOS JSON (en formato BSON internamente). Un documento se ve como un objeto JavaScript: { nombre: 'Ana', edad: 25, hobbies: ['leer', 'programar'] }. Los documentos similares se agrupan en COLECCIONES (equivalente a las tablas, pero sin esquema fijo). Cada documento tiene un _id único (UUID).

Concepto SQLConcepto MongoDBDiferencia clave
Base de datosBase de datosIgual.
TablaColecciónLa colección NO tiene esquema fijo.
Fila (registro)DocumentoEs un objeto JSON/BSON.
ColumnaCampoCada documento puede tener campos distintos.
Primary key_idSe genera automáticamente como ObjectId.
JOINLookup (desde 3.2) o embebidoMongoDB prefiere datos embebidos.
Foreign keyReferencia (ObjectId de otro documento)Sin integridad referencial automática.
⭐ Sin esquema fijo = poder y responsabilidad: MongoDB NO TIENE esquema fijo. Puedes tener un documento con { nombre, edad } y otro con { nombre, email, redes_sociales } en la MISMA colección. Esto es una VENTAJA (flexibilidad) y una DESVENTAJA (puedes tener datos inconsistentes). Mongoose (que verás pronto) te da validación opcional para resolver esto: tú decides cuán estricto quieres ser.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.9.3 Mongoose: el ODM para Node.js

Mongoose es el ODM (Object Document Mapper) más popular para MongoDB con Node.js. Te da schemas con validación, modelos con métodos, queries con chaining, y middlewares. Es lo que necesitas para usar MongoDB con Node de forma profesional. Aprende Mongoose, no el driver nativo (que es más verboso).

// models/Usuario.js: schema y modelo de Mongoose
import mongoose from 'mongoose';

// Definir el SCHEMA (estructura y validación)
const usuarioSchema = new mongoose.Schema({
  nombre: {
    type: String,
    required: [true, 'El nombre es obligatorio'],
    trim: true,
    minlength: 2,
    maxlength: 100,
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    match: [/^\S+@\S+\.\S+$/, 'Email inválido'],
  },
  edad: {
    type: Number,
    min: [0, 'La edad no puede ser negativa'],
    max: 120,
  },
  activo: { type: Boolean, default: true },
  hobbies: [String],  // array de strings
  redes: {  // documento embebido
    twitter: String,
    github: String,
  },
  creadoEn: { type: Date, default: Date.now },
});

// Crear el MODELO (la clase con la que interactúas)
export const Usuario = mongoose.model('Usuario', usuarioSchema);

Schema y modelo con Mongoose

⭐ Schema = definición, Modelo = clase: Schema vs Modelo: el schema es la DEFINICIÓN (estructura, validación, tipos), el modelo es la CLASE con la que interactúas. Mongoose hace el mapeo automático: 'Usuario' en singular se mapea a la colección 'usuarios' en plural (agrega 's' automáticamente). Es uno de los detalles más elegantes de Mongoose.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.9.4 CRUD con Mongoose

Las 4 operaciones CRUD con Mongoose son muy similares a las de SQL, pero con sintaxis moderna de JavaScript. Mongoose devuelve Promises, así que puedes usar async/await. La sintaxis es limpia y potente.

import { Usuario } from './models/Usuario.js';

// CREATE: crear un usuario
const ana = await Usuario.create({
  nombre: 'Ana López',
  email: 'ana@mail.com',
  edad: 25,
  hobbies: ['leer', 'programar'],
  redes: { twitter: '@ana', github: 'anita' },
});

// READ: buscar usuarios
const todos = await Usuario.find({ activo: true });  // array
const ana   = await Usuario.findOne({ email: 'ana@mail.com' });  // un documento
const porId = await Usuario.findById('65abc...');  // por _id

// Con filtros, proyección, populate, etc.:
const adultos = await Usuario
  .where('edad').gte(18)
  .where('activo').equals(true)
  .select('nombre email')  // solo estos campos
  .sort('-creadoEn')       // descendente
  .limit(10)
  .populate('posts');      // reemplaza ObjectId con documento

// UPDATE: actualizar
const actualizado = await Usuario.findByIdAndUpdate(
  id,
  { edad: 26 },
  { new: true, runValidators: true }  // devuelve el nuevo y valida
);

// DELETE: eliminar
const eliminado = await Usuario.findByIdAndDelete(id);

CRUD completo con Mongoose

⭐ Dos estilos de query: Mongoose tiene dos formas de definir queries: (1) la tradicional con métodos encadenados (find().where().select().sort().limit()), o (2) la moderna con await Usuario.find({...}, { filtros }). Ambas funcionan, pero la tradicional es más legible para queries complejas. La moderna es más concisa para queries simples. Conoce ambas.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.9.5 Modelado: embebido vs referencias

La decisión más importante en MongoDB: ¿guardo los datos EMBEBIDOS (subdocumentos) o como REFERENCIAS (ObjectId a otro documento)? Cada enfoque tiene trade-offs. La regla general: embebido para datos que SIEMPRE se leen juntos y son únicos del documento padre; referencias para datos que pueden existir independientemente o se consultan solos.

Caso de usoEmbebidoReferencia
Usuario con sus direcciones (siempre juntos)
Usuario con sus posts (1 usuario tiene N posts)
Post con sus comentarios (siempre con el post)
Producto con su categoría (1 producto → 1 categoría)
Pedido con sus items (siempre juntos)
// EMBEBIDO: el comentario vive DENTRO del post
const post = {
  titulo: 'Mi primer post',
  autor: 'Ana',
  comentarios: [
    { usuario: 'Luis', texto: '¡Genial!', fecha: new Date() },
    { usuario: 'Sofía', texto: 'Me encantó', fecha: new Date() },
  ],
};
// Para obtener el post con sus comentarios: 1 query.

// REFERENCIA: los posts se guardan en su propia colección
// y el usuario solo guarda los ObjectIds
const usuario = {
  nombre: 'Ana',
  posts: [
    ObjectId('65abc123...'),  // referencia al post
    ObjectId('65def456...'),
  ],
};
// Para obtener el usuario con sus posts: 2 queries + populate
// populate('posts') reemplaza los ObjectIds con los documentos completos

Embebido vs Referencia en código

⭐ Embebido por defecto, referencia si es necesario: La regla del 80% en MongoDB: embebido por defecto, referencia cuando sea estrictamente necesario. Embebido es más rápido (1 query en vez de 2+), más simple (no necesitas populate), y más intuitivo. Referencia solo cuando: (1) los datos son grandes (> 16MB por documento), (2) se consultan independientemente, (3) se comparten entre muchos documentos. Si dudas, embebe.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.9.6 MongoDB Atlas: la BD en la nube gratis

MongoDB Atlas es la versión 'managed' de MongoDB en la nube: tú solo creas la BD y Atlas se encarga de backups, escalabilidad, actualizaciones, y seguridad. Tiene un plan gratuito (M0) con 512 MB de almacenamiento: suficiente para aprender, hacer proyectos pequeños, y tener tu BD accesible desde cualquier lugar del mundo sin instalar nada localmente.

Cómo conectar tu app a MongoDB Atlas

// .env (variables de entorno, NO subir a Git)
MONGODB_URI=mongodb+srv://usuario:password@cluster0.xxxxx.mongodb.net/mi_app?retryWrites=true&w=majority

// db.js: conexión con Mongoose
import mongoose from 'mongoose';

const conectarDB = async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URI);
    console.log('Conectado a MongoDB Atlas');
  } catch (error) {
    console.error('Error de conexión:', error.message);
    process.exit(1);
  }
};

export default conectarDB;

// server.js: llamar antes de iniciar Express
import conectarDB from './db.js';
conectarDB().then(() => {
  app.listen(3000, () => console.log('Servidor en puerto 3000'));
});

Conexión a MongoDB Atlas con Mongoose

⭐ .env + .gitignore SIEMPRE: NUNCA hardcodees la URI de MongoDB en tu código. Usa SIEMPRE variables de entorno (.env + dotenv). Si subes la URI a Git, cualquiera puede acceder a tu BD. La URI contiene el usuario y password en texto plano. Agrega .env a .gitignore desde el inicio. Es la regla #1 de seguridad.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

📚 Contenido ampliado

Material adicional, referencias externas verificadas y ejemplos extendidos.

🤖 AI Mission

MongoDB se aprende modelando datos del mundo real, no leyendo sobre NoSQL.

Misión: Diseña el schema de Mongoose para una 'red social de libros': Usuario, Libro, Reseña, ListaDeLectura. Decide qué va embebido y qué va como referencia. Crea los modelos, implementa 5 operaciones CRUD, y conéctalo a MongoDB Atlas. Pídele a la IA que revise tu modelado. Anota en tu cuaderno: ¿qué decisiones de embebido vs referencia tomaste y por qué?

Pasos sugeridos

  1. Diseña los 4 modelos: Usuario, Libro, Resena, ListaDeLectura.
  2. Decide embebido vs referencia: ¿reseñas embebidas en libro? ¿autores referenciados?
  3. Crea carpeta 'red-social-libros'. npm init -y. type:module.
  4. Instala: npm install express mongoose dotenv.
  5. Crea .env con tu URI de MongoDB Atlas. Agrégalo a .gitignore.
  6. Crea models/Usuario.js, models/Libro.js, models/Resena.js, models/Lista.js con schemas.
  7. Crea routes/ con CRUD para libros y reseñas.
  8. Conecta a MongoDB Atlas y prueba crear/ leer / actualizar / eliminar.
  9. Decide: ¿qué parte embebiste? ¿qué referenciaste? ¿por qué?
  10. Pídele a la IA: 'Tengo este modelado en Mongoose para una red social de libros. Sugiere 2 mejoras: embebido vs referencia, índices, o validación. NO me des código, dime QUÉ cambiar y POR QUÉ.'
  11. Aplica 2 mejoras. Vuelve a probar.
  12. Anota en tu cuaderno: 3 decisiones clave de modelado que tomaste y por qué.

📓 Entregable: URL de MongoDB Atlas con datos de prueba, capturas de las 5 operaciones CRUD, código de los modelos, y media página de cuaderno con tus decisiones de modelado.

🚫 Errores típicos de razonamiento

Error 1: Hardcodear la URI de MongoDB en el código.
Por qué: Si pones la URI de MongoDB con usuario y password en tu código y la subes a Git, CUALQUIERA puede acceder a tu BD. La URI tiene las credenciales en texto plano. Solución: usa SIEMPRE variables de entorno (.env + dotenv) y agrega .env a .gitignore desde el inicio. Es la regla #1 de seguridad en cualquier proyecto.
Error 2: Referenciar todo en vez de embeber.
Por qué: Es tentador usar referencias para 'ser correcto', pero embebido es más rápido y simple. La regla del 80%: embebido por defecto, referencia solo cuando los datos son grandes, se consultan independientemente, o se comparten entre muchos. Si dudas, embebe. Un post con sus 50 comentarios embebidos es más rápido que 2 queries + populate.
Error 3: Olvidar crear índices en campos de búsqueda frecuente.
Por qué: Si haces Usuario.find({ email: 'x' }) sin índice en email, MongoDB hace collection scan (revisa TODOS los documentos). Con índice, lo encuentra en milisegundos. En Mongoose: usuarioSchema.index({ email: 1 }) o unique: true en el campo (que crea índice automáticamente). Regla: índice en todos los campos que uses en find() frecuentemente.
Error 4: No usar validación en los schemas de Mongoose.
Por qué: Mongoose te da validación gratuita: required, minlength, maxlength, match, min, max, enum. Si no las usas, tu BD se llena de datos basura: emails inválidos, edades negativas, nombres vacíos. La validación en el schema es tu primera línea de defensa. Sin ella, tienes que validar manualmente en cada ruta (tedioso e inconsistente).
Error 5: Escribir queries que devuelven TODOS los documentos sin paginación.
Por qué: Si tu colección tiene 1 millón de documentos y haces Usuario.find({}) sin paginación, MongoDB intenta enviarte 1 millón de documentos a tu app, saturando la memoria. USA SIEMPRE .limit() y .skip() (o paginación por cursor). Para el 95% de las UIs, 20-50 resultados por página es suficiente.

🧪 Laboratorio práctico

MongoDB se aprende modelando datos, no leyendo sobre NoSQL.

Laboratorio: API de red social de libros con Express + MongoDB

Objetivo: Construir una API REST de gestión de libros con Express, Mongoose y MongoDB Atlas. Implementar CRUD de libros, agregar reseñas embebidas, búsqueda por título, y filtros por género. Practicarás: schemas, modelos, queries, validación, y conexión a MongoDB Atlas.

Pasos

  1. Crea cuenta en MongoDB Atlas (gratis M0). Crea cluster y usuario.
  2. Obtén la connection string y guárdala en .env.
  3. Crea 'api-libros-mongo'. npm init -y. type:module. Instala express mongoose dotenv.
  4. Crea models/Libro.js con schema (titulo, autor, genero, anio, resenas embebidas, puntuacion promedio).
  5. Crea routes/libros.js con CRUD: listar (paginado), ver, crear, actualizar, eliminar.
  6. Crea routes/resenas.js: POST /libros/:id/resenas (embebida).
  7. Crea db.js con la conexión a MongoDB Atlas.
  8. Crea server.js con Express, middlewares, y rutas montadas.
  9. Implementa búsqueda: GET /libros?genero=Ciencia Ficcion&titulo=... con regex.
  10. Implementa validación: required en titulo y autor, min:1900 max:2100 en anio.
  11. Crea índices: titulo, genero, autor.
  12. Inserta 20 libros de prueba. Prueba todas las rutas con curl.
  13. Sube a Railway/Render. Comparte la URL pública.
  14. Haz commit: 'feat: API de libros con Express + Mongoose + MongoDB Atlas'.

📓 Entregable: URL pública de la API en producción, capturas de las 5 operaciones CRUD, capturas de MongoDB Atlas con la colección, código de los modelos, y commit en Git.

📓 Tu cuaderno: Anota pseudocódigo, diagramas, errores que encontraste y respuestas a "explica sin código". La escritura manual refuerza tu razonamiento. Tu profesor puede pedirte que subas fotos de páginas específicas.