How to create a custom many to many relationship in TypeORM
Tags: typescript, beginners, database, tutorial
Published: 2021-08-03 01:23:36

<b>Hi guys</b>, how are you today? I hope you are fine!

![Big Hero Hug](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x1086a6u7tctsi7chp6s.gif)

<hr>

####Preface

<b>Many-to-many</b> relationships are quite common when you're developing any kind of app, from food stores to large inventory.

Most of the time this relationship is not simple and you need to add more information in the pivo table (table generated from the relationship). We will learn how to make this custom relationship using typeORM.

<hr>

####Concepts

First of all let's review some concepts:

The purpose of <b>typeORM</b> is to support JavaScript features that help you develop any type of application that uses databases - from small applications with a few tables to large-scale enterprise applications with multiple databases.

The many-to-many relationship infers that A can have many B and B can have many A. In other words, both sides can report a variety on the other side.

<hr>

####To work

After all the initial configuration of typeORM, we need to generate the models and migrations.

In this example, we will build heroes that can have different individualities.

![Midoriya,boku no hero](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3a6it0y33kmoai6mtfw.gif)


We can create <b>models</b> with the following command:

```
typeorm  entity:create -n Hero
```

Our hero will have a name and skills. Put this in your model:

```

@Entity("heros")
class Hero {
  @PrimaryGeneratedColumn("increment")
  id: number;

  @Column({ length: 30 })
  name: string;

  @ManyToMany(() => Skill)
  @JoinTable({
    name: "hero_skills",
  })
  skills: Skill[];
}

export default Hero;

```
<br>
<center><i>src/models/Hero.ts</i></center>
<br>

and...

```
typeorm  entity:create -n Skill
```

```
@Entity("skills")
class Skill {
  @PrimaryGeneratedColumn("increment")
  id: number;

  @Column()
  skill: string;
}

export default Skill;
```
<br>
<center><i>src/models/Skill.ts</i></center>
<br>

<b>And here comes the magic, let's create a model to reference the relationship!</b>

```
typeorm  entity:create -n HeroSkills
```

And inside let's put:


```
@Entity("hero_skills")
class HeroSkills {

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

  @Column({ type: "int" })
  episode: number;

  @PrimaryColumn({ type: "int" })
  skills_id: number;

  @PrimaryColumn({ type: "int" })
  heros_id: number;

  @OneToOne(() => Hero)
  @JoinTable()
  hero: Hero;

  @OneToOne(() => Skill)
  @JoinTable()
  skill: Skill;
}

export default HeroSkills;

```
<br>
<center><i>src/models/HeroSkills.ts</i></center>
<br>

In this case, we'll show you when a hero first demonstrated his individuality and what he looks like.

<b>Let's do migrations now</b>


```
typeorm migration:create -n CreateHeroTable
```

```
...
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: "heros",
        columns: [
          {
            name: "id",
            type: "int",
            isPrimary: true,
            generationStrategy: "increment",
          },
          {
            name: "name",
            type: "varchar",          
          },
          {
            name: "skills_id",
            type: "int",          
          },
        ],
        foreignKeys: [
          {
            name: "Skills",
            referencedTableName: "skills",
            referencedColumnNames: ["id"],
            columnNames: ["skills_id"],
            onDelete: "CASCADE",
            onUpdate: "CASCADE",
          },
        ],
      })
    );
  }
...
```
<br>
<center><i>src/database/migrations/<time>CreateHeroTable.ts</i></center>
<br>

Note that the foreign key relationship is explicit.

*In the case of a many-to-many relationship, it does not matter in which table the relationship will be explicit, as long as the relationship exists

```
....
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: "skills",
        columns: [
          {
            name: "id",
            type: "int",
            isPrimary: true,
            generationStrategy: "increment",
          },
          {
            name: "skill",
            type: "varchar",
          },
        ],
      })
    );
  }
...
```
<br>
<center><i>src/database/migrations/<time>CreateSkillsTable.ts</i></center>
<br>

Now let's go to the relational migration:

```
typeorm migration:create -n CreateHeroSkillsTable
```
```
...
 await queryRunner.createTable(
      new Table({
        name: "hero_skills",
        columns: [
          {
            name: "id",
            type: "int",
            isPrimary: true,
            generationStrategy: "increment",
          },
          {
            name: "description",
            type: "text",
          },
          {
            name: "episode",
            type: "int",
          },
          {
            name: "heros_id",
            type: "int",
          },
          {
            name: "skills_id",
            type: "int",
          },
        ],
        foreignKeys: [
          {
            name: "Hero",
            referencedTableName: "heros",
            referencedColumnNames: ["id"],
            columnNames: ["heros_id"],
            onDelete: "CASCADE",
            onUpdate: "CASCADE",
          },
          {
            name: "Skill",
            referencedTableName: "skills",
            referencedColumnNames: ["id"],
            columnNames: ["skills_id"],
            onDelete: "CASCADE",
            onUpdate: "CASCADE",
          },
        ],
      })
    );
...
```

And finally run:

```
typeorm migration:run
```


If all goes well, all tables will be created with their respective relationships!

![All might congrats](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7g15kqlc5n5m72zm5ara.gif)

<center>Time is very important, thanks for sharing a little bit of yours with me 😊.</center>

<a style="float: left;" href="https://github.com/devneto">![image](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)</a>

<a style="float: left;" href="https://twitter.com/_devneto">![image](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)</a>