Tipado de Documentos Embebidos en NestJS con Mongoose
Clase 21 de 24 • Curso de NestJS: Persistencia de Datos con MongoDB
Contenido del curso
Database
- 4

Configuración y ejecución de MongoDB con Docker Compose
08:51 min - 5

Conexión a Base de Datos MongoDB con Mongo Compass
05:05 min - 6

Instalación y conexión de MongoDB en Node con driver oficial
06:59 min - 7

Inyección de Conexiones MongoDB en Servicios NestJS
06:57 min - 8

Consultas a MongoDB con Nest.js: Implementación de Endpoints
04:46 min - 9

Variables de Entorno para Configuración de MongoDB en Node.js
10:43 min
Mongoose
- 10

Instalación y Configuración de Mongoose con NestJS
07:52 min - 11

Definición de Esquemas en Mongoose para eCommerce con NestJS
07:45 min - 12

Operaciones CRUD con MongoDB y Node.js en un Servicio de Productos
09:29 min - 13

Creación, actualización y eliminación de productos en MongoDB
10:12 min - 14

Validación de MongoID con Pipes en NestJS
06:38 min - 15

Paginación en MongoDB con DTOs y Validaciones en NestJS
11:13 min - 16

Consultas Avanzadas con Rangos de Precios en MongoDB
07:30 min - 17

Indexación en MongoDB: Cómo optimizar consultas rápidas
03:11 min
Relaciones en MongoDB
- 18

Relaciones embebidas en MongoDB: Manejo y ejemplos prácticos
07:55 min - 19

Relaciones uno a uno referenciadas en MongoDB
12:20 min - 20

Relaciones Uno a Muchos en MongoDB: Arrays Embebidos vs Referenciados
09:28 min - 21

Tipado de Documentos Embebidos en NestJS con Mongoose
Viendo ahora - 22

Relaciones Uno a Muchos Referenciadas en MongoDB
14:36 min - 23

Manipulación de Arrays en E-commerce: Métodos y Endpoints
13:08 min
Próximos pasos
En las relaciones embebidas usamos las siguientes dos formas:
Para relaciones 1:1 embebidas:
@Prop( raw({ name: { type: String }, image: { type: String }, }), ) category: Record<String, Any>;
Para relaciones 1:N embebidas:
@Prop({ type: [{ name: { type: String }, color: { type: String } }], }) skills: Types.Array<Record<String, Any>>;
Sin embargo en los dos usamos any lo cual hace que no tengamos un tipado en estos documentos embebidos, por eso vamos a ver otra forma de lograrlo.
La solución
Lo primero es que vamos a crear un esquema para ese documento embebido, de esta manera:
// src/products/entities/sub-doc.entity.ts import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; @Schema() export class SubDoc { @Prop() name: String; @Prop() description: String; } export const SubDocSchema = SchemaFactory.createForClass(SubDoc);
Con su respectivo DTO:
// src/products/dtos/sub-doc.dto.ts import { IsString, IsNotEmpty } from 'class-validator'; import { PartialType } from '@nestjs/swagger'; export class CreateSubDocDto { @IsString() @IsNotEmpty() readonly name: String; @IsString() @IsNotEmpty() readonly description: String; } export class UpdateSubDocDto extends PartialType(CreateSubDocDto) {}
Luego importamos este SubDoc dentro de la entidad que queramos que maneje la relación, así:
// src/products/entities/product.entity.ts import { SubDoc, SubDocSchema } from './sub-doc.entity'; // 👈 import ... export class Product extends Document { ... @Prop({ type: SubDocSchema }) subDoc: SubDoc; // 👈 new field (1:1) @Prop({ type: [SubDocSchema] }) subDocs: Types.Array<SubDoc>; // 👈 new field (1:N) } ...
Debes tener en cuenta que este SubDoc no va a estar declarado en el módulo, ya que es un documento embebido y no una colección.
Con esto ya tienes el objeto embebido con tipado y además lo puedes incluir en tus DTOS para una validación más poderosa, de la siguiente manera:
// src/products/dtos/products.dtos.ts import { ..., IsArray } from 'class-validator'; import { Type } from 'class-transformer'; // 👈 transform import { CreateSubDocDto } from './sub-doc.dto'; // 👈 import export class CreateProductDto { ... @IsNotEmpty() @ValidateNested() readonly subDoc: CreateSubDocDto; // 👈 1:1 @IsNotEmpty() @IsArray() @ValidateNested({ each: true }) @Type(() => CreateSubDocDto) readonly subDocs: CreateSubDocDto[]; // 👈 1:N }
En este punto puedes crear un producto con un documento embebido de forma tipada y con una validación profunda, puedes ver esta forma en la rama 18 del proyecto por si quieres revisar el código a más detalle.
Si haces un POST te debería resultar algo así: