Search code examples
nestjstypeorm

How to delete nested entities in TypeORM and Nest.js


I have one-to-many relation:

class User {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @OneToMany(() => Phone, phone => phone.user, {cascade: true})
    phones?: Phone[];
}

Assume current data in database is following: user has two phone numbers:

{
  "id": 1,
  "name": "Jhon",
  "phones": [
    {"id": 1, "phone":  "123456"},
    {"id": 2, "phone":  "567809"}
  ]
}

I build UI (web-interface) and from web-interface I want to have possibility to delete a phone number from user profile. So I do it and following POST request comes from UI: second phone number deleted

{
  "id": 1,
  "name": "Jhon",
  "phones": [
    {"id": 1, "phone":  "123456"}
  ]
}

How to delete phone number id=2 from database? I use Nest CRUD module, as I understand from source code it just merges a new data from request with current data from database, so merging two phone numbers from database with the only phone number from request gives us array of tho phone numbers again and nothing deleted :frowning: I tried to do it manually and there are a lot of code!

  @Override()
  async updateOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: UpdateUserDto,
    @Param('id') id: number,
  ): Promise<Shipment> {

    // use standart Nest.js way to save new user data into database
    await this.service.updateOne(req, dto);

    // load fresh user data from database
    const user = await this.service.findOne(id);

    const phonesFromUi = dto.phones;
    const phonesToBeDeleted = [];
    // loop phone numbers from database - detect which to be deleted
    user.phones.forEach((phoneFromDb) => {
      const hasThisPhoneOnUi = phonesFromUi.find((phoneFromUi) => phoneFromUi.id === phoneFromDb.id);
      if (!hasThisPhoneOnUi) {
        // looks like this phone number was deleted on ui, so delete it from database too
        phonesToBeDeleted.push(phoneFromDb);
      }
    });
    // actually delete phone numbers from database
    await this.connection.getRepositoryFor(Phone).remove(phonesToBeDeleted);

    // reload fresh user data from database to get fresh list of phone numbers after delition some of them
    const user = await this.service.findOne(id);

    return user;
  }

Is there any way to do it via TypeORM build in functions or methods? How to delete some elements from nested array?


Solution

  • There is no very good support in typeorm for doing a join update, what I advise you to do is receiving the phones parameter and get a select of the phones that are related to the UserId and then delete the ids that are not in the new array:

    const phones = await this.phoneRepository.find({userId:1});
    const toDeletePhones = phones.filter((element)) => {
      return updatePhones.indexOf(element) === -1;
    }
    this.phoneRepository.remove(toDeletePhones);
    

    then procede to update the user or yo can even do it before this