Relaciones embebidas en MongoDB: Manejo y ejemplos prácticos

Clase 18 de 24Curso de NestJS: Persistencia de Datos con MongoDB

Contenido del curso

Mongoose

Resumen

Trabajar con bases de datos no relacionales como MongoDB no significa renunciar a conectar información entre entidades. Aunque no existen relaciones transaccionales como en PostgreSQL o MySQL, MongoDB ofrece formas eficientes de vincular datos, y la más común en bases de datos documentales es la relación embebida: un documento dentro de otro documento.

¿Qué son las relaciones embebidas en MongoDB?

Cuando un producto necesita una categoría asociada, en lugar de crear una tabla aparte y usar foreign keys, simplemente se incluye un subdocumento con la información de la categoría dentro del documento del producto. Esta es la estrategia más utilizada en bases de datos documentales y resulta muy práctica.

Por ejemplo, un producto puede contener directamente un objeto category con propiedades como name e image. No hay una referencia externa: toda la información vive en el mismo documento.

¿Cómo se define un subdocumento con Mongoose en NestJS?

Para manejar relaciones embebidas en el esquema de Mongoose, se utiliza el decorador raw [01:42]. Este decorador permite definir un subobjeto directamente dentro del esquema principal:

  • Se importa raw desde Mongoose/NestJS.
  • Se crea una nueva propiedad category con el tipo Record<string, any>.
  • Dentro del decorador @Prop, se usa raw() para especificar los atributos del subdocumento.

El subdocumento de categoría queda definido con dos campos:

  • name: de tipo string.
  • image: de tipo string.

De esta forma, Mongoose entiende que category no es un campo simple sino un objeto embebido con su propia estructura.

¿Cómo se valida un DTO anidado con class-validator?

El siguiente paso es asegurar que al crear un producto también se valide correctamente la información de la categoría embebida. Aquí entra en juego el concepto de validación en cascada con el decorador @ValidateNested() de class-validator [04:07].

El proceso es el siguiente:

  • Se agrega image al DTO de categoría (CreateCategoryDTO) con la validación @IsUrl(), ya que se necesita una dirección válida.
  • Se importa CreateCategoryDTO dentro de CreateProductDTO.
  • Se añade una propiedad category de tipo CreateCategoryDTO con los decoradores @ValidateNested() y @IsNotEmpty().

Esto significa que las validaciones del DTO de categoría se ejecutan automáticamente cuando se valida el DTO del producto. Si el cliente envía category como un string en lugar de un objeto, la validación lo rechaza. Si envía un objeto vacío, también lo rechaza indicando que faltan name e image.

¿Cómo se comporta la creación en la práctica?

Al probar el endpoint de creación en Insomnia [05:15], las validaciones funcionan paso a paso:

  • Sin category: el servidor responde que el campo no puede estar vacío.
  • Con category como string: indica que debe cumplir restricciones anidadas.
  • Con category como objeto vacío: exige name e image.
  • Con todos los campos completos: el producto se crea exitosamente con la categoría embebida.

Al verificar en Mongo Compass [06:30], el documento almacenado muestra category como un objeto con name e image, confirmando que la relación embebida quedó almacenada correctamente.

¿Es válido repetir información en bases de datos no relacionales?

Un punto fundamental: en bases de datos no relacionales no es incorrecto duplicar información [06:55]. Si muchos productos comparten la misma categoría y cada uno almacena una copia del subdocumento, esto es perfectamente aceptable. Es parte del diseño documental y favorece la velocidad de lectura al evitar joins costosos.

Sin embargo, también existe la posibilidad de usar relaciones referenciadas, donde en lugar de embeber el documento completo se almacena solo un identificador que apunta a otro documento en una colección separada. Esta alternativa es útil cuando la información referenciada cambia con frecuencia o se comparte entre muchas entidades.

Si te interesa conocer cómo implementar relaciones referenciadas uno a uno en MongoDB con NestJS, comparte tu experiencia con relaciones embebidas y cuéntanos en qué casos las has utilizado.