Update a many-to-many relationship with TypeORM

Jonathan picture Jonathan · Jan 10, 2019 · Viewed 11k times · Source

I am having issues updating a entity that has a many-to-many reln, curious if I am doing something wrong, or more specifically what is the right way to do this

Consider the following entities ...

@Entity
class Subject
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  name: string;

  @ManyToMany(() => Note, note => note.subjects)
  @JoinTable()
  notes: Note[];

  ...

@Entity()
export class Note {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @ManyToMany(() => Subject, (subject: Subject) => subject.notes)
  subjects: Subject[];

In my code I find the node and then try to update it and save like so ...

const note = await noteRepo.findOneOrFail(noteId);
const foundSubjects = await subjectRepo.findByIds(Array.from(subjectIds));
note.subjects = foundSubjects;
noteRepo.save(note);

But alas, the subjects are not saved on the note.

What is the right way to do this?

Thanks!

Answer

Nestor Perez picture Nestor Perez · Aug 9, 2019

In my case Im trying to update an existing relation but that gives me a unique key violation because the relation already exists, so I first need to remove all existing relationships and then add the relationships of my updated user:

export const updateUser = async (user: User): Promise<User | undefined> => {
    /**
     * Get the actual relationships of that user.
     */
    const actualRelationships = await getRepository(User)
        .createQueryBuilder()
        .relation(User, 'roles')
        .of(user).loadMany();

    /**
     * Add new relationships of the user, and delete the old relationships.
     */
    await getRepository(User)
        .createQueryBuilder()
        .relation(User, 'roles')
        .of(user)
        .addAndRemove(user.roles, actualRelationships);

    /**
     * Update only the table USER.
     */
    await getRepository(User)
        .createQueryBuilder()
        .update()
        .set({
            name: user.name,
            username: user.username,
            active: user.active
        })
        .where('id = :id', {id: user.id})
        .execute();

    /**
     * Return the updated user
     */
    return await getUser(user.id, true, true)
};