TypeORM一对多关联查询异常:如何获取包含指定两用户的Chat
问题描述
我正在使用TypeORM开发聊天系统,数据实体定义如下:
@Entity() export class Chat { @PrimaryGeneratedColumn('uuid') id: string; @OneToMany(() => Participant, (participant) => participant.chat) participant: Participant[]; @OneToMany(() => Message, (message) => message.chat) messages: Message[]; @CreatedDateColumn() created_at: Date; } @Entity() export class Participant { @PrimaryGeneratedColumn('uuid') id: string; @ManyToOne(() => UserEntity, (user) => user.id) @JoinColumn({ name: 'user_id' }) user: UserEntity; @ManyToOne(() => Chat, (chat) => chat.participants) @JoinColumn({ name: 'chat_id'}) chat: Chat; } @Entity() export class Message { @PrimaryGeneratedColumn('uuid') id: string; @ManyToOne(() => Chat, (chat) => chat.messages) @JoinColumn({ name: 'chat_id'}) chat: Chat; @Column() text: string; @CreatedDateColumn() created_at: Date; }
当前使用的查询语句:
const chat = await this.chatRepository.findOne({ relations: { participants: true, }, where: { participants: { user: In([creteMessageDto.user1, createMessageDto.user2]) } } })
该查询仅在user1和user2在Participant表中各出现一次时正常工作,当用户多次出现在Participant表中时,会返回错误的Chat。需要编写能准确返回包含user1和user2两个参与者的Chat的查询语句。
解决方案
原查询的问题在于,In条件会匹配包含任意一个目标用户的Chat,而非同时包含两个用户的Chat。要实现准确查询,需要通过分组和计数来确保Chat同时包含两个用户:
方法1:使用QueryBuilder(推荐)
const chat = await this.chatRepository .createQueryBuilder('chat') .leftJoinAndSelect('chat.participants', 'participant') .leftJoinAndSelect('participant.user', 'user') .where('user.id IN (:...userIds)', { userIds: [createMessageDto.user1, createMessageDto.user2] }) .groupBy('chat.id') .having('COUNT(DISTINCT user.id) = :userCount', { userCount: 2 }) .getOne();
方法2:使用Repository的findOne选项
如果偏好使用Repository的查询选项,可以通过多条件组合结合计数校验实现:
const chat = await this.chatRepository.findOne({ relations: { participants: { user: true } }, where: [ { participants: { user: { id: createMessageDto.user1 } } }, { participants: { user: { id: createMessageDto.user2 } } } ], having: { participants: { $count: 2 } } });
关键说明
- QueryBuilder方式逻辑更清晰,通过分组后计数,确保Chat恰好包含指定的两个用户(若需支持N人聊天,只需调整
userCount的值)。 - 使用
DISTINCT避免同一用户多次加入同一Chat导致计数错误。 - 一对一聊天场景用
COUNT(DISTINCT user.id) = 2,群聊场景可改为>= userCount适配多用户需求。
内容的提问来源于stack exchange,提问作者Vasyl Savchuk
相关产品推荐
相关产品推荐

