databáze - Jak filtrovat a počítat položky vztahu v TypeORM?
V mém projektu mám službu pro oznámení událostí. Entity vypadají takto.
@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;
}
Třídy User a Event jsou entity s relacemi jeden-ku-mnohým, jak můžete vidět v deklaraci entity, a fungují správně s databází PostgreSQL.
Musím najít všechny uživatelské objekty s počtem jejich nepřečtených událostí.
Prozatím toho dosahuji tím, že najdu všechny uživatele s jejich událostmi a ručně spočítám nepřečtené události pomocí pole readAt v entitě události.
Takto:
...
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);
);
...
Vím, že je to špatná praxe, a jsem si docela jistý, že toho mohu dosáhnout pomocí funkcí TypeOrm, ne ručním počítáním.
Jediné, co mohu udělat, je filtrování nepřečtených zpráv v objektech uživatelů.
...
constructor(@InjectRepository(User) private userRepository: Repository<User>) { }
...
const found = await this.usersRepository.createQueryBuilder('user')
.leftJoinAndSelect('user.events', 'events')
.where('events.readAt is null')
.getMany();
...
Ale i toto má své omezení. Uživatelské objekty bez nezpracovaných událostí nejsou tímto dotazem vráceny.
Každá pomoc bude oceněna.
Aplikace je vytvořena pomocí frameworku NestJs a celý kód je napsán v TypeScriptu.
Děkuji předem.
Odpověď č. 1
Zkuste :
const found = await this.usersRepository.createQueryBuilder('user')
.loadRelationCountAndMap('user.unreadEventCount', 'user.events', 'event', (qb) => qb.where('event.readAt IS NULL'))
.getMany();
O loadRelationCountAndMap:
Prvým argumentem je název vlastnosti, ke které bude počet přiřazen - to by bylo pole na vaší entitě, které NENÍ @Column.
Druhé je název vztahu
3. je alias, který se má použít s dotazem
Čtvrtý je volitelný QueryBuilder pro další filtrování, ve vašem případě kontroluje, zda je sloupec readAt nulový
