使用 TypeORM / NestJS 删除 manytomany table 中的一行

removing a single row in a manytomany table with TypeORM / NestJS

我有一个包含两个实体的 nestJS 项目,一个用户实体和一个聊天室实体,一个聊天室中可以有多个用户,用户可以在多个聊天室中,这里是聊天室实体:

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

    @Column()
    name: string;

    @Column('int', {array: true, default: []})
    public adminId: number[];

    @Column()
    ownerId: number;

    @ManyToMany(() => User, { cascade: true, onUpdate:'CASCADE' })
    @JoinTable()
    users: User[];
}

和用户实体:

@Entity()
export class User {
  @PrimaryColumn()
  public id: number;
 
  @Column({nullable: true})
  public username: string;

  @Column()
  public log: string;

  @Column({default: 0})
  public rank: number;

  @Column('int', {array: true, default: []})
  public blocked: number[];

  @ManyToMany(() => ChatRoom, room => room.users)
  rooms: ChatRoom[];
}

现在 querybuilder 我设法获取了聊天室中的用户列表并获取了用户已加入的聊天室列表,但是我想知道如何删除单个关系,如果用户想要离开房间,如何在不删除用户实体或聊天室实体本身的情况下删除匹配行?

这是我为了从聊天室的用户列表中删除特定用户而编写的初始聊天室服务代码:

async removeUserFromRoom(user: User, roomid: number)
    {
        const room = await this.chatRepo.findOne(roomid);
        if (room)
        {
            room.users = room.users.filter(user => {
                user.id !== user.id
            })
            await this.chatRepo.save(room);
        }
        else
            throw new HttpException('Room not found', HttpStatus.NOT_FOUND);
    }

虽然此解决方案不起作用,因为房间实体没有定义用户数组,但我是否需要 运行 查询才能从聊天室中删除用户?或者有没有办法在 TypeORM 中处理这个问题?如果我似乎误解了什么,请告诉我,因为我对数据库和查询比较陌生。

您的 room 实体没有 users 数组,因为您在使用存储库时没有查询关系。

const room = await this.chatRepo.findOne(roomid, { relations: ['users'] }); 应该可以解决这个问题。

根据文档,删除似乎只能从 'owning' 端进行。

根据您的需要,您可以:

使用当前模型,您需要从用户那里删除房间。 (是的,这在语法上是不正确的,但它说明了你必须做什么。)

所以你要搜索房间里的用户,而不是用户的房间。

const user = await this.userRepo.findOne(userid); 

但是...您有用户,所以:

    async removeUserFromRoom(user: User, roomid: number) 
    {
        //TODO: refresh user data
        user.rooms.filter(room => {
            room.id != roomid
        })
        await this.userRepo.save(user);
    }

重要的事情

您需要分析用例,因为您可能会发现将 @JoinTable() 移动到 User 实体更有效。

但是等等...

你搞砸了,房间里没有定义的用户。所以:

  • 你已经定义了它们(它们可能已经卸载了。很容易检查,只需使用console.log(await room.users)

  • 您的代码中有一个错误:您定义了 user 变量两次。在主要功能和过滤器中。最后,条件 user.id != user.id 始终是 true 因为您比较了过滤器中的用户。

顺便说一句:

出于性能原因,由于相关记录的潜在数量,我会将 'owning' 端移至 'User'。 (通常每个频道的用户比频道用户前多)