3.3 · MongoDB y Mongoose : base NoSQL

Nivel 3 · Express y bases de datos

3.3MongoDB y Mongoose : base NoSQL

Objetivo: persistir datos con MongoDB y Mongoose : conexión, esquemas validados, modelos, y CRUD completo asíncrono — el paso que transforma un servidor en una aplicación real.
Tiempo estimado: 12 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

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.

Error frecuente de interpretación: « MongoDB sin esquema significa sin ninguna regla, y los métodos Mongoose son síncronos ». No. Sin esquema Mongoose, los datos se vuelven rápido incoherentes (campos y tipos divergentes) ; el esquema aporta validación y rechazos limpios. Y todos los métodos CRUD devuelven Promesas : sin await, se manipula una promesa pendiente, no el documento.
MongoDB + Mongoose Flexibilidad del documento, rigor del esquema DocumentosJSON/BSON en colecciones+EsquemaTipos + required/unique+Modelo + CRUDcreate, find, update, delete en await El esquema valida antes de registrar ; el CRUD es async.
Flexibilidad del documento, rigor del esquema
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Documentos : Salim guarda sus productos en objetos flexibles en una colección. 2) Esquema : impone nombre requerido y precio positivo vía Mongoose. 3) Modelo + CRUD : create, findById, update y delete en await, con populate para las reseñas vinculadas. Lección : la flexibilidad NoSQL vive bajo control del esquema.

🔎 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

  1. Conectaos a MongoDB con mongoose.connect(uri) (base local o MongoDB Atlas en la nube, URI ficticia en ejercicio).
  2. Definid un esquema (tipos + validaciones : required, unique) y cread un modelo con mongoose.model('User', userSchema).
  3. Realizad un CRUD completo (asíncrono, con await) : create (crear), find/findById (leer), findByIdAndUpdate (modificar), findByIdAndDelete (suprimir).
  4. Explorad las consultas (filtros, orden, paginación) y una relación entre documentos (referencia + populate).
Persistís datos con MongoDB y Mongoose : conexión, esquemas validados, modelos, y CRUD completo asíncrono — el paso que transforma un servidor en una aplicación real.

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.

Prudencia: Conexión y secretos : usad una URI ficticia o local para aprender (p. ej. mongodb://127.0.0.1:27017/demo-catalogue) y no peguéis jamás una URI real ni una contraseña en el código, las capturas o los mensajes. En producción, la URI vive en una variable de entorno fuera del repositorio, con un usuario de derechos mínimos. En caso de exposición accidental, regenerad el secreto y cambiad la contraseña antes de toda reconexión.

✓ 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.

Lista de salida de la sección
  • Distingo documento/colección de tabla/fila.
  • Mi esquema valida required y tipos.
  • Mi CRUD es async con await.
Autoevaluación 1-5 : ¿rechaza mi esquema los datos inválidos?¿están mis secretos fuera del código (URI ficticia)?

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.

Comprueba tu comprensión

¿Qué hace el esquema Mongoose para unos datos MongoDB?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 3Preguntas inéditas y más difíciles para validar tus conocimientos