3.3MongoDB y Mongoose : base NoSQL
Lo esencial en 30 segundos
- MongoDB almacena documentos : objetos tipo JSON/BSON en colecciones, sin esquema rígido — cercanos a los objetos JavaScript.
- Mongoose añade el rigor : esquema (tipos + validaciones required/unique) y luego modelo que ofrece los métodos de manipulación.
- El CRUD es asíncrono : create, find/findById, findByIdAndUpdate, findByIdAndDelete con await, más consultas, populate y hooks.
Mini-caso hilado — Salim almacena su catálogo sin caos
Salim, desarrollador junior en Argel, guardaba su catálogo en una tabla en memoria : todo desaparece en cada reinicio. Pasa a MongoDB : conexión vía mongoose.connect con una URI ficticia de trabajo, esquema de producto (nombre requerido, precio número positivo, categoría por defecto), modelo Produit, y luego CRUD completo en await. Cuando falta un campo email o un precio es negativo, la validación Mongoose rechaza antes del registro. Se acabaron los datos fantasiosos.
Este mismo caso vuelve en el curso, el esquema, el guion y el reto 48h.
1. MongoDB, base orientada a documentos
Una app real debe persistir sus datos : MongoDB, base NoSQL orientada a documentos muy popular con Node, almacena documentos (estructuras tipo JSON/BSON) agrupados en colecciones — sin tablas ni filas, sin esquema rígido impuesto por la base. Un documento se parece a { nom: 'Théière', prix: 2400 } : flexible, anidable, natural para un desarrollador JavaScript.
Esta flexibilidad es una baza (estructuras evolutivas, prototipado rápido) pero también un riesgo : sin disciplina, los documentos divergen (campos renombrados, tipos mezclados). De ahí la capa Mongoose — y la elección NoSQL frente a SQL (sección 3-4) según la naturaleza de los datos : flexibles y poco relacionales → MongoDB ; fuertemente vinculados y críticos → SQL.
2. Mongoose : esquemas, modelos, CRUD async
Se trabaja vía Mongoose, un ODM que viste a MongoDB. El esquema define la forma esperada con tipos y validaciones : new mongoose.Schema({ nom: String, email: { type: String, required: true, unique: true } }). El modelo creado desde el esquema (mongoose.model('User', userSchema)) ofrece los métodos : create / new + save, find / findById, findByIdAndUpdate, findByIdAndDelete — todos asíncronos, luego con await.
Mongoose gestiona también las consultas (filtros, orden, paginación), las relaciones (referencias + populate para unir) y los hooks (ejecutar código antes/después, como cifrar una contraseña antes del registro — sección 4-2). Reflejo de Salim : definir siempre un esquema aunque MongoDB no lo exija, y jamás contraseña ni URI real en el código compartido.
🔎 Ejemplo concreto — Esquema, modelo y CRUD validado
Salim persiste su primer producto con validación.
const mongoose = require('mongoose');
// URI FICTICIA pedagógica — jamás una URI real en el código compartido
await mongoose.connect('mongodb://127.0.0.1:27017/demo-catalogue');
const produitSchema = new mongoose.Schema({
nom: { type: String, required: true },
prix: { type: Number, min: 0 }
});
const Produit = mongoose.model('Produit', produitSchema);
const p = await Produit.create({ nom: 'Théière', prix: 2400 });
const lu = await Produit.findById(p._id);
Lectura : conexión, esquema validado, modelo, y luego create/findById en await.
Lección : un dato inválido lo rechaza el esquema antes de la base.
Vocabulario de la sección
- Persistencia
- Guardado duradero de los datos en una base (usuarios, productos…) en vez de la memoria volátil.
Ejemplo sencillo: El catálogo de Salim conservado tras el reinicio.
Lo que no es: una tabla JS vaciada en cada parada del servidor.
Reflejo: persistir en cuanto el dato deba sobrevivir.
- MongoDB (NoSQL documento)
- Base que almacena documentos tipo JSON/BSON en colecciones, sin esquema rígido ; flexible y cercana al JS.
Ejemplo sencillo: La colección de productos con documentos variados.
Lo que no es: una tabla SQL de columnas estrictas y joins.
Reflejo: considerarla para datos flexibles y evolutivos.
- Mongoose (ODM)
- Capa práctica sobre MongoDB : esquemas validados, modelos, consultas, relaciones y hooks.
Ejemplo sencillo: El esquema de producto de Salim con required y min.
Lo que no es: el driver en bruto sin validación ni modelos.
Reflejo: pasar por Mongoose para el rigor diario.
- Esquema y modelo
- El esquema define estructura y validaciones ; el modelo, creado desde el esquema, ofrece los métodos CRUD.
Ejemplo sencillo: produitSchema luego mongoose.model('Produit', produitSchema).
Lo que no es: documentos lanzados a la base sin forma declarada.
Reflejo: declarar tipos, required y unique antes del primer create.
- CRUD async
- Create, Read, Update, Delete vía métodos Mongoose asíncronos (await) : create, find, findByIdAndUpdate, findByIdAndDelete.
Ejemplo sencillo: await Produit.create(...) luego findById.
Lo que no es: llamadas síncronas imaginarias sin await.
Reflejo: await sistemático y gestión de error try/catch.
En la práctica — Persistir datos con MongoDB y Mongoose
- Conectaos a MongoDB con mongoose.connect(uri) (base local o MongoDB Atlas en la nube, URI ficticia en ejercicio).
- Definid un esquema (tipos + validaciones : required, unique) y cread un modelo con mongoose.model('User', userSchema).
- Realizad un CRUD completo (asíncrono, con await) : create (crear), find/findById (leer), findByIdAndUpdate (modificar), findByIdAndDelete (suprimir).
- Explorad las consultas (filtros, orden, paginación) y una relación entre documentos (referencia + populate).
Guion listo para decir — presentar su persistencia Mongo (30 s)
« El catálogo está persistido bajo MongoDB : conexión mongoose, esquema de producto con nombre requerido y precio positivo, modelo Produit, CRUD completo en await. La validación rechaza los datos inválidos antes de la base, y pruebo sobre una URI local ficticia, jamás secreto real en el código. »
Para decir en demo ; mostrar un create rechazado por la validación.
Modelo copiar-pegar — Mongoose CRUD (URI ficticia)
const mongoose = require('mongoose');
// URI FICTICIA — ejemplo pedagógico, sustituir en local, secreto en variable de entorno
const URI_FACTICE = 'mongodb://127.0.0.1:27017/demo-catalogue';
async function main() {
await mongoose.connect(URI_FACTICE);
const produitSchema = new mongoose.Schema({
nom: { type: String, required: true },
prix: { type: Number, min: 0, required: true }
});
const Produit = mongoose.model('Produit', produitSchema);
const cree = await Produit.create({ nom: 'Théière', prix: 2400 });
const lu = await Produit.findById(cree._id);
await Produit.findByIdAndUpdate(cree._id, { prix: 2600 });
await Produit.findByIdAndDelete(cree._id);
await mongoose.disconnect();
}
main().catch(console.error);
Independiente
Un solo modelo Mongoose validado basta para fiabilizar los presupuestos almacenados.
Pyme en Argel
Salim modela productos y reseñas vinculados, con populate para mostrar las reseñas por producto.
Equipo de producto
Imponer required/unique en el esquema para que cada equipo escriba datos coherentes.
Principiante
Esta semana : un esquema de dos campos y un CRUD create + find en await.
✓ Buenas prácticas
- Definir siempre un esquema Mongoose (rigor + validación).
- Usar el CRUD asíncrono con await.
- Cifrar las contraseñas vía un hook antes del registro (ver 4.2).
✗ Errores frecuentes
- Renunciar al esquema con el pretexto de que MongoDB es « flexible » (datos caóticos).
- Aceptar cualquier campo enviado por un cliente (riesgo de inyección de campos).
- Olvidar que los métodos Mongoose son asíncronos (await).
Puntos clave
- Una aplicación real PERSISTE sus datos. Dos familias : NoSQL (MongoDB) y SQL/relacional (3-4).
- MongoDB (NoSQL orientado a DOCUMENTOS) almacena documentos tipo JSON/BSON en COLECCIONES — flexible, cercano a los objetos JS.
- MONGOOSE (ODM) añade esquemas (estructura + VALIDACIÓN) y modelos (métodos) : rigor Y flexibilidad.
- CRUD asíncrono (await) : create / find(ById) / findByIdAndUpdate / findByIdAndDelete ; también consultas, relaciones (populate), hooks.
Reto 48h — aplica mañana
Definid 1 esquema Mongoose con 2 validaciones y realizad un CRUD create + find en await.
- Distingo documento/colección de tabla/fila.
- Mi esquema valida required y tipos.
- Mi CRUD es async con await.
Preguntas frecuentes
¿MongoDB (NoSQL) o SQL : cómo elegir?
Según la naturaleza de los datos. MongoDB conviene a los datos flexibles y evolutivos, a las estructuras anidadas cercanas al JSON, al prototipado rápido y a los datos poco relacionales. El SQL conviene a los datos fuertemente relacionales (muchos joins), a la integridad crítica (esquema estricto, transacciones ACID) y a las consultas cruzadas complejas. Ni una ni otra es universalmente mejor : Salim empieza en MongoDB para su catálogo flexible y guarda el SQL (3.4) para la facturación vinculada.
¿Por qué usar Mongoose en vez de MongoDB directo, y hacen falta esquemas?
Mongoose aporta esquemas + validación (rechazo de datos incoherentes antes del registro), modelos y métodos elegantes (CRUD, filtros, orden, paginación, populate), hooks (cifrar una contraseña antes del save) y una API coherente. Sí, definid esquemas aunque MongoDB no lo imponga : sin ellos, campos renombrados y tipos mezclados garantizan el caos. La flexibilidad queda (campos opcionales, estructuras anidadas), pero bajo control.
¿Qué hace el esquema Mongoose para unos datos MongoDB?