Introducción

1

¿Ya terminaste el Curso de NestJS: Programación Modular?

2

Platzi Store: presentación del proyecto e instalación

Database

3

Cómo instalar Docker para este proyecto

4

Configuración de PostgresSQL en Docker

5

Explorando postgres con interfaces gráficas y terminal

6

Integración de node-postgres con NestJS

7

Conexión como inyectable y ejecutando un SELECT

8

Usando variables de ambiente

TypeORM

9

¿Qué es un ORM? Instalando y configurando TypeORM Module

10

Creando tu primera entidad

11

TypeORM: active record vs. repositories

12

Crear, actualizar y eliminar

13

Cambiar a Mysql demo (opcional)

Migraciones

14

Sync Mode vs. Migraciones en TypeORM

15

Configurando migraciones y npm scripts

16

Corriendo migraciones

17

Modificando una entidad

Relaciones

18

Relaciones uno a uno

19

Resolviendo la relación uno a uno en el controlador

20

Relaciones uno a muchos

21

Resolviendo la relación uno a muchos en el controlador

22

Relaciones muchos a muchos

23

Resolviendo la relación muchos a muchos en el controlador

24

Manipulación de arreglos en relaciones muchos a muchos

25

Relaciones muchos a muchos personalizadas

26

Resolviendo la relación muchos a muchos personalizada en el controlador

Consultas

27

Paginación

28

Filtrando precios con operadores

29

Agregando indexadores

30

Modificando el naming

31

Serializar

Migración a NestJS 9 y TypeORM 0.3

32

Actualizando Dependencias para NestJS 9

33

Cambios en TypeORM 0.3

34

Migraciones en TypeORM 0.3

Próximos pasos

35

Cómo solucionar una referencia circular entre módulos

36

Continúa con el Curso de NestJS: Autenticación con Passport y JWT

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Relaciones uno a muchos

20/36
Recursos

Aportes 8

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

He creado dos snippets de VS Code para crear un Servicio y un Controller básico mucho más rápido. (para hacer lo que el profe hace en cámara rápida).

Para crearlos van a:

  • File
  • Preferences
  • User Snippets
  • Buscan typescript

En el archivo JSON que se les abrió copian este código dentro de las llaves:

  • Servicio
	"Create NestJS Service": {
		"prefix": "nest:s",
		"body": [
			"import { Injectable, NotFoundException } from '@nestjs/common';",
			"import { InjectRepository } from '@nestjs/typeorm';",
			"import { Repository } from 'typeorm';",
			"",
			"import { $2 } from '${1:entity-route}';",
			"import { ${4:createDto}, ${5:updateDto} } from '${3:dto-route}';",
			"",
			"@Injectable()",
			"export class ${6:serviceName}Service {",
			"  constructor(",
			"    @InjectRepository($2)",
			"    private ${7:repo}: Repository<$2>,",
			"  ) {}",
			"${0}",
			"  async findAll() {",
			"    return await this.$7.find();",
			"  }",
			"",
			"  async findOne(id: number) {",
			"    const ${8:object} = await this.$7.findOne(id);",
			"    if (!$8) throw new NotFoundException(`${9:object} not found.`);",
			"    return $8;",
			"  }",
			"",
			"  async create(data: $4) {",
			"    const ${10:newObject} = this.$7.create(data);",
			"    return await this.$7.save($10);",
			"  }",
			"",
			"  async update(id: number, changes: $5) {",
			"    const $8 = await this.findOne(id);",
			"    this.$7.merge($8, changes);",
			"    return await this.$7.save($8);",
			"  }",
			"",
			"  async remove(id: number) {",
			"    return await this.$7.delete(id);",
			"  }",
			"}",
		],
		"description": "This service has a basic CRUD implemented"
	},
  • Controller
"Create NestJS Controller": {
		"prefix": "nest:co",
		"body": [
			"import {",
			"  Controller,",
			"  Get,",
			"  Post,",
			"  Put,",
			"  Body,",
			"  Param,",
			"  Delete,",
			"  ParseIntPipe,",
			"} from '@nestjs/common';",
			"import { ApiTags } from '@nestjs/swagger';",
			"",
			"import { ${2:serviceName} } from '${1:service-route}';",
			"import { ${4:createDto}, ${5:updateDto} } from '${3:dto-route}';",
			"",
			"@ApiTags('${6:controllerName}')",
			"@Controller('$6')",
			"export class ${7:controllerNameInUppercase}Controller {",
			"  constructor(private ${8:serviceName}: $2) {}",
			"",
			"  @Get()",
			"  async findAll() {",
			"    return await this.$8.findAll();",
			"  }",
			"",
			"  @Get('/:id')",
			"  async getCategory(@Param('id') id: number) {",
			"    return await this.$8.findOne(id);",
			"  }",
			"",
			"  @Post()",
			"  async create(@Body() payload: $4) {",
			"    return await this.$8.create(payload);",
			"  }",
			"",
			"  @Put('/:id')",
			"  async update(",
			"    @Param('id', ParseIntPipe) id: number,",
			"    @Body() payload: $5,",
			"  ) {",
			"    return await this.$8.update(id, payload);",
			"  }",
			"",
			"  @Delete('/:id')",
			"  async remove(@Param('id', ParseIntPipe) id: number) {",
			"    return await this.$8.remove(id);",
			"  }",
			"}",
		],
		"description": "This controller has a basic CRUD implemented"
	}

Para usarlos simplemente tienen que crear su servicio/controlador normalmente y borrar lo que hay ahí.
Luego simplemente ponen nest:s o nest:co y empiezan a llenar todos los datos que se pide.
Para avanzar solo precionen la tecla tab

Espero les sirva! 😃

Lo que vimos:

brand.entity.ts

import {
  PrimaryGeneratedColumn,
  Column,
  Entity,
  CreateDateColumn,
  UpdateDateColumn,
  OneToMany,
} from 'typeorm';
import { Product } from './product.entity';

@Entity()
export class Brand {
  @PrimaryGeneratedColumn()
  id: number;
  @Column({ type: 'varchar', length: 255, unique: true })
  name: string;

  @Column({ type: 'varchar', length: 255 })
  image: string;

  @CreateDateColumn({
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  createAt: Date;

  @UpdateDateColumn({
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  updateAt: Date;

  @OneToMany(() => Product, (product) => product.brand)
  products: Product;
}


brands.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { Brand } from '../entities/brand.entity';
import { CreateBrandDto, UpdateBrandDto } from '../dtos/brand.dtos';

@Injectable()
export class BrandsService {
  constructor(@InjectRepository(Brand) private brandRepo: Repository<Brand>) {}
  findAll() {
    return this.brandRepo.find();
  }

  async findOne(id: number) {
    const product = await this.brandRepo.findOne(id);
    if (!product) {
      throw new NotFoundException(`Brand #${id} not found`);
    }
    return product;
  }

  create(data: CreateBrandDto) {
    const newBrand = this.brandRepo.create(data);
    return this.brandRepo.save(newBrand);
  }

  async update(id: number, changes: UpdateBrandDto) {
    const brand = await this.brandRepo.findOne(id);
    this.brandRepo.merge(brand, changes);
    return this.brandRepo.save(brand);
  }

  remove(id: number) {
    return this.brandRepo.delete(id);
  }
}

product.entity.ts

import {
  PrimaryGeneratedColumn,
  Column,
  Entity,
  CreateDateColumn,
  UpdateDateColumn,
  ManyToOne,
} from 'typeorm';
import { Brand } from './brand.entity';

@Entity()
export class Product {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'varchar', length: 255, unique: true })
  name: string;

  @Column({ type: 'text' })
  description: string;

  @Column({ type: 'int' })
  price: number;

  @Column({ type: 'int' })
  stock: number;

  @Column({ type: 'varchar' })
  image: string;

  @CreateDateColumn({
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  createAt: Date;

  @UpdateDateColumn({
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  updateAt: Date;

  @ManyToOne(() => Brand, (brand) => brand.products)
  brand: Brand;
}

El @JoinColumn se podría usar si necesitamos los nombres de las columnas foráneas personalizadas.
Teniendo como ejemplo un grupo que tiene subgrupos, si queremos que al ejecutar la migración y crear la columna no se llame “grupoId” , sino que se llame “grupo_id”. Ejemplo:

// grupos.entity.ts
@OneToMany(() => SubGroup, (subgroup) => subgroup.grupo)
 subgrupos: SubGroup[]

//subgrupos.entity.ts
@ManyToOne(() => Group, (group) => group.subgrupos)
@JoinColumn({ name: 'grupo_id' })
grupo: number

Si les sale el error "Cannot find a module Brand.entity, es porque nest al realizar la autoimportacion del archivo los hace utilizando rutas absolutas. Para solucionarlo deben modificar las importaciones utilizando rutas relativas.

Relaciones uno a muchos

Vamos a trabajar ahora en relaciones uno a muchos (1: n), para esto vamos a tomar como caso de ejemplo la relación de productos a marcas, ya que una marca puede tener muchos productos, pero un producto solo puede tener una marca.

En las relaciones uno a muchos, la entidad débil (1), es la que por defecto debe tener la relación, en este caso la entidad débil el nuestro Product:

  • src/products/entities/product.entity.ts:
import {
  // ..
  ManyToOne,
} from 'typeorm';

// importamos la entidad que vamos a referenciar
import { Brand } from './brand.entity';

@Entity()
export class Product {
  // ...

  // el decorador "ManyToOne" indica la relacíon muchos a uno
  // muchos productos, una marca
  // indicamos que resuelva la entidad "Brand" con una arrow function
  // indicamos el atributo que maneja la relación "brand.products"
  @ManyToOne(() => Brand, (brand) => brand.products)
  brand: Brand;
}

Recordemos que TypeORM nos permite manejar relaciones bidireccionales, así que vamos a la entidad de las Brands e indiquemos esta relación bidireccional.

  • src/products/entities/brand.entity.ts:
import {
  // ...
  OneToMany,
} from 'typeorm';
import { Product } from './product.entity';

@Entity()
export class Brand {
  // ..

  // el decorador "OneToMany" indica la  relación uno a muchos
  // una marca, muchos productos
  // indicamos que resuelva la entidad "Product" con una arrow function,
  // indicamos el atributo que maneja la relación "product.brand"
  @OneToMany(() => Product, (product) => product.brand)
  products: Product[];
}

En este caso no debemos añadir un decorador extra que sea el que maneje la clave foránea como lo es **@JoinColumn()**, debido a que TypeORM sabe que en las relaciones uno a muchos es la entidad débil la que maneja la relación “@ManyToOne()" es la que tiene que tener la clave foránea.

Ahora solo debemos crear una migración y ya habremos definido nuestra relación uno a muchos.

super chistoso escuchar la musica en 1.5x ademas de tener el volumen alto, llegué a saltar jajaja

Excelente clase, cada día aprendiendo mas sobre Manejo de bases de datos con nextjs lml

Consulta, no entendi porque hiciste Nico una relacion bidireccional entre product y brand, alguien me lo puede explicar mas sencillo? jajaja

Al final la entidad debil es la que tiene la relación, esto es 'Product' porque un producto solo puede tener una marca pero una marca puede tener muchos productos