如何在typeorm中过滤和统计关系项?

11 database typescript typeorm nestjs

我的项目中有一个事件通知服务。实体看起来像这样。


@Entity('event')
class Event {
    @Column()
    message: string;

    @Column()
    readAt: Date;

    @ManyToOne(() => User, user => user.events)
    user: User;
}

@Entity('user')
class User {
    @PrimaryGeneratedColumn()
    id: string;

    @Column()
    email: string;

    @Column()
    fullName: string;

    @OneToMany(() => Event, event => event.user)
    events: Event[];

    unread: number;
}
Run Code Online (Sandbox Code Playgroud)

UserEvent是具有一对多关系的实体,正如您在实体声明中看到的那样,并且可以在 PostgreSQL 数据库中正常工作。

我必须找到所有用户对象及其未读事件计数。

目前,我通过查找所有用户及其事件并使用readAt事件实体中的字段手动计算未读事件来实现此目的。

像这样:

...
const users = await this.userRepository.find({ relations: ['events'] });

users.forEach(user => {
   user.unread = user.events.reduce((cnt, event) => {
      if (event.readAt) { return cnt + 1; }
      return cnt;
   }, 0);
);
...
Run Code Online (Sandbox Code Playgroud)

我知道这是一个不好的做法,并且我非常确定我可以使用 TypeOrm 功能来实现这一点,而不是通过手动计数。

我唯一能做的就是过滤用户对象中的未读消息。

...
constructor(@InjectRepository(User) private userRepository: Repository<User>) { }
...
const found = await this.usersRepository.createQueryBuilder('user')
   .leftJoinAndSelect('user.events', 'events')
   .where('events.readAt is null')
   .getMany();
...
Run Code Online (Sandbox Code Playgroud)

但这也有其局限性。此查询不会返回没有任何未读事件的用户对象。

任何帮助,将不胜感激。

该应用程序是使用 NestJs 框架制作的,所有代码都是用 typescript 编写的。

先感谢您。

pio*_*ura 16

尝试:

const found = await this.usersRepository.createQueryBuilder('user')
   .loadRelationCountAndMap('user.unreadEventCount', 'user.events', 'event', (qb) => qb.where('event.readAt IS NULL'))
   .getMany();
Run Code Online (Sandbox Code Playgroud)

关于loadRelationCountAndMap

第一个参数是计数将映射到的属性名称 - 这将是实体上的一个字段,而不是 @Column。

第二个是关系名称

第三个是用于查询的别名

第四个是可选的 QueryBuilder 来进一步过滤,在您的情况下,它检查readAt列是否为空