Search code examples
typescriptnestjstypeorm

TypeORM - Many-to-Many-to-One


First off, forgive me if I'm using the wrong terms to describe this question. I'm learning.

When I query companies, I want to include the addresses and I would like for the address to include the address type.

So, I think I'm asking for the best way to include a one-to-one "along with" the results of a many-to-many.

My tables (slightly sanitized for illustration):

  +------------------+--------------+----------------------------+
  |                              company                         |
  +------------------+--------------+----------------------------+
  | id               | int          | PRIMARY KEY AUTO_INCREMENT |
  | name             | varchar(255) |                            |
  +------------------+--------------+----------------------------+

  +------------------+--------------+----------------------------+
  |                          company_address                     |
  +------------------+--------------+----------------------------+
  | company_id       | int          |                            |
  | address_id       | int          |                            |
  +------------------+--------------+----------------------------+

  +------------------+--------------+----------------------------+
  |                              address                         |
  +------------------+--------------+----------------------------+
  | id               | int          | PRIMARY KEY AUTO_INCREMENT |
  | name             | varchar(255) |                            |
  | address_type_id  | int          |                            |
  +------------------+--------------+----------------------------+

  +------------------+--------------+----------------------------+
  |                           address_type                       |
  +------------------+--------------+----------------------------+
  | id               | int          | PRIMARY KEY AUTO_INCREMENT |
  | name             | varchar(255) |                            |
  +------------------+--------------+----------------------------+

When I query addresses, I am able to grab the address type using the following in my Address entity:

...
    @OneToOne(() => AddressType)
    @JoinColumn({ name: "address_type_id" })
    addressType: AddressType;
...

while using the following relations in the Address service:

...
  async findOne(id: number): Promise<Address> {
    return this.addressesRepository.findOne(id,{ relations: ["addressType"] });
  }
...

When I query company, I am able to grab the address using the following in my Company entity. However, it doesn't include the address type:

...
    @ManyToMany(() => Address)
    @JoinTable({
        name:"company_address",
        joinColumn: {
            name: "company_id",
            referencedColumnName: "id"
        },
        inverseJoinColumn: {
            name: "address_id",
            referencedColumnName: "id"
        }
    })
    addresses: Address[];
...

while using the following relations in the Company service:

...
  async findOne(id: number): Promise<Company> {
    return this.companiesRepository.findOne(id,{ relations: ["addresses"] });
  }
...

Initially I thought that it would "just work" from the entity definition for Address. However, the addressType column is missing from the results.


Solution

  • relations field in the FindOptions object can also take sub-relations. As the example in the given link shows, you need to add addresses.addressType to your relation array to include that relation in the results:

    async findOne(id: number): Promise<Company> {
      return this.companiesRepository.findOne(id,
        {
          relations: ["addresses", "addresses.addressType"]
        });
    }