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 muchos a muchos

22/36
Recursos

Aportes 5

Preguntas 1

Ordenar por:

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

Apuntes

category.entity

// src\products\entities\category.entity.ts
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";

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

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

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

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

category.service

// src\products\services\categories.service.ts

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

import { Category } from '../entities/category.entity';
import { CreateCategoryDto, UpdateCategoryDto } from '../dtos/category.dtos';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { merge } from 'rxjs';

@Injectable()
export class CategoriesService {
  constructor(
    @InjectRepository(Category) private categoryRepo: Repository<Category>
  ){}

  findAll() {
    return this.categoryRepo.find();
  }

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

  create(data: CreateCategoryDto) {
    const newCategory = this.categoryRepo.create(data);
    return this.categoryRepo.save(newCategory);
  }

  async update(id: number, changes: UpdateCategoryDto) {
    const category = await this.findOne(id);
    this.categoryRepo.merge(category, changes);
    return this.categoryRepo.save(category);
  }

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

products module


// src\products\products.module.ts
@Module({
...
// Agregamos a category
  imports:[TypeOrmModule.forFeature([Product, Brand, Category])],
...
})

Creando la relacion

// src\products\entities\category.entity.ts
@ManyToMany(()=>Product, (product)=>product.categories)
@JoinTable() // Solo debe estar en una entidad
products: Product[]

// src\products\entities\product.entity.ts
@ManyToMany(()=>Category, (category)=>category.products)
categories: Category[];

Crear y correr la migracion

npm run migrations:generate -- create-categories
npm run migrations:run

Tal vez les sirva para nombrar las columnas de las relaciones.

@JoinColumn

Defines which side of the relation contains the join column with a foreign key and allows you to customize the join column name and referenced column name. Example:

@Entity()
export class Post {

@ManyToOne(type => Category)
@JoinColumn({
    name: "cat_id",
    referencedColumnName: "name"
})
category: Category;

}

@JoinTable

Used for many-to-many relations and describes join columns of the “junction” table. Junction table is a special, separate table created automatically by TypeORM with columns referenced to the related entities. You can change the name of the generated “junction” table and also the column names inside the junction table and their referenced columns with the joinColumn- and inverseJoinColumn attributes. Example:

@Entity()
export class Post {

@ManyToMany(type => Category)
@JoinTable({
    name: "question_categories",
    joinColumn: {
        name: "question",
        referencedColumnName: "id"
    },
    inverseJoinColumn: {
        name: "category",
        referencedColumnName: "id"
    }
})
categories: Category[];

}

Relaciones muchos a muchos

TypeORM nos permite maneja relaciones muchos a muchos, recordemos que para manejar relaciones muchos a muchos es necesario una tabla ternaría que nos permita manejar esta relación. Pero TypeORM ya nos abstrae este concepto de la tabla ternaría.

Para esto usaremos como caso de ejemplo las categorías y los productos, ya que un producto puede tener distintas categorías, y una categoría puede tener distintos productos.

Para esto, vamos a modificar primero la entidad de los productos:

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

// importamos la entidad a la cual queremos hacer la relación
import { Category } from './category.entity';

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

  // Este decorador especifica que la relación va a ser muchos a muchos
  // resuleve la envidad a la qu va a hacer referencia con una arrow function
  // debemos especificar en que atributo resuelve la entidad
  @ManyToMany(() => Category, (category) => category.products)
  categories: Category[];
}

Para crear la relación muchos a muchos, es obligatorio que le especifiquemos una comunicación bidireccional a la otra entidad, sin embargo, deberíamos procurar hacer esto siempre debido a que es una buena práctica el que ambas entidades tengan una comunicación bidireccional.

  • **src/products/entities/category.entity.ts**:
import {
  // ...
  ManyToMany,
} from 'typeorm';

// importamos la entidad a la cual queremos hacer la relación
import { Product } from './product.entity';

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

  // hacemos la relación bidireccional
  // resuleve la envidad a la qu va a hacer referencia con una arrow function
  // debemos especificar en que atributo resuelve la entidad
  @ManyToMany(() => Product, (products) => products.categories)
  products: Product[];
}

Ya hemos comunicado las entidades y que tipo de relación tienen, ahora, para crear la tabla donde se especificará la relación muchos a muchos, debemos utilizar el decorador **@JoinTable()**, es importante aclarar que este decorador debe ir en solo una de las entidades, puede ser la que quieras, en mi caso quiero que sea en los productos:

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

import { Category } from './category.entity';

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

  @ManyToMany(() => Category, (category) => category.products)
	// este decorador crea la tabla terniaria
  @JoinTable()
  categories: Category[];
}

Y listo, ahora con crear y correr una migración nos basta para que esta.

Para personalizar los nombres de las tablas y llaves o referencias de la tabla

/user.entity.ts
@OneToOne(() => Customer, (customer) => customer.user, { nullable: true })
  @JoinColumn({
    name: "pk_customer",
    referencedColumnName: "id"
  })
  customer: Customer
/category.entity.ts
@ManyToMany(() => Product, (products) => products.categories, { nullable: true })
  products: Product[];
/product.entity.ts
 @ManyToOne(() => Brand, (brand) => brand.products, { nullable: true })
  brand: Brand

  @ManyToMany(() => Category, (categories) => categories.products, { nullable: true })

  @JoinTable({
    name: "product_categories",
    joinColumn: {
      name: "pk_product",
      referencedColumnName: "id"
    },
    inverseJoinColumn: {
      name: "pk_category",
      referencedColumnName: "id"
    }
  })
  categories: Category[];

Product Entity

@Entity()
export class Product extends BasicEntity {
  @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;

  @ManyToOne(() => Brand, (brand) => brand.products, { nullable: true })
  // La que tiene relacion many to one, tiene la llave foranea @JoinColumn()
  brand: Brand;

  @ManyToMany(() => Category, (category) => category.products, {
    nullable: false,
  })
  // La que tiene relacion many to one, tiene la llave foranea @JoinColumn()
  categories: Category[];
}

Category entity


@Entity()
export class Category extends BasicEntity {
  @PrimaryGeneratedColumn()
  id: number;

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

  @ManyToMany(() => Product, (product) => product.categories)
  @JoinTable() //Este decorador solo debe ir en un lado de la migración
  products: Product[];
}