🎯 Objetivo del tema
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.
El paradigma opuesto a SQL: documentos, no tablas.
BSON, colecciones, _id, embebido vs referenciado.
Schemas, modelos, validación, y queries modernas.
Las 4 operaciones en sintaxis moderna.
La decisión más importante en MongoDB.
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.
| Aspecto | SQL (PostgreSQL, MySQL) | NoSQL (MongoDB) |
|---|---|---|
| Modelo de datos | Tablas con filas y columnas. | Documentos JSON flexibles. |
| Esquema | Fijo: defines columnas al crear la tabla. | Flexible: cada documento puede tener campos distintos. |
| Relaciones | Foreign keys, JOINs. | Embebido (subdocumentos) o referencias (manual). |
| Escalabilidad | Vertical (más CPU/RAM). | Horizontal (más servidores). |
| Transacciones | ACID completas. | Solo multi-documento desde MongoDB 4.0. |
| Cuándo usarlo | Datos estructurados, transacciones críticas. | Datos flexibles, alto volumen, esquemas cambiantes. |
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 SQL | Concepto MongoDB | Diferencia clave |
|---|---|---|
| Base de datos | Base de datos | Igual. |
| Tabla | Colección | La colección NO tiene esquema fijo. |
| Fila (registro) | Documento | Es un objeto JSON/BSON. |
| Columna | Campo | Cada documento puede tener campos distintos. |
| Primary key | _id | Se genera automáticamente como ObjectId. |
| JOIN | Lookup (desde 3.2) o embebido | MongoDB prefiere datos embebidos. |
| Foreign key | Referencia (ObjectId de otro documento) | Sin integridad referencial automática. |
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
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
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 uso | Embebido | Referencia |
|---|---|---|
| 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 completosEmbebido vs Referencia en código
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
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
- Diseña los 4 modelos: Usuario, Libro, Resena, ListaDeLectura.
- Decide embebido vs referencia: ¿reseñas embebidas en libro? ¿autores referenciados?
- Crea carpeta 'red-social-libros'. npm init -y. type:module.
- Instala: npm install express mongoose dotenv.
- Crea .env con tu URI de MongoDB Atlas. Agrégalo a .gitignore.
- Crea models/Usuario.js, models/Libro.js, models/Resena.js, models/Lista.js con schemas.
- Crea routes/ con CRUD para libros y reseñas.
- Conecta a MongoDB Atlas y prueba crear/ leer / actualizar / eliminar.
- Decide: ¿qué parte embebiste? ¿qué referenciaste? ¿por qué?
- 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É.'
- Aplica 2 mejoras. Vuelve a probar.
- 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
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.
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.
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.
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).
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
- Crea cuenta en MongoDB Atlas (gratis M0). Crea cluster y usuario.
- Obtén la connection string y guárdala en .env.
- Crea 'api-libros-mongo'. npm init -y. type:module. Instala express mongoose dotenv.
- Crea models/Libro.js con schema (titulo, autor, genero, anio, resenas embebidas, puntuacion promedio).
- Crea routes/libros.js con CRUD: listar (paginado), ver, crear, actualizar, eliminar.
- Crea routes/resenas.js: POST /libros/:id/resenas (embebida).
- Crea db.js con la conexión a MongoDB Atlas.
- Crea server.js con Express, middlewares, y rutas montadas.
- Implementa búsqueda: GET /libros?genero=Ciencia Ficcion&titulo=... con regex.
- Implementa validación: required en titulo y autor, min:1900 max:2100 en anio.
- Crea índices: titulo, genero, autor.
- Inserta 20 libros de prueba. Prueba todas las rutas con curl.
- Sube a Railway/Render. Comparte la URL pública.
- 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.