如何在TypeORM中左连接时限制关联子实体数量?
在Nest.js+TypeORM+PostgreSQL中实现用户关联最多5张照片的查询
实体关联确认
首先确保你的User和Photo实体的一对多关系配置正确:
User 实体
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; import { Photo } from './photo.entity'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(() => Photo, photo => photo.user, { eager: false }) photos: Photo[]; }
Photo 实体
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; import { User } from './user.entity'; @Entity() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() url: string; @Column() createdAt: Date; // 可选,用于自定义排序 @ManyToOne(() => User, user => user.photos) user: User; @Column() userId: number; // 外键字段,必须存在 }
查询实现方案
由于TypeORM默认关联查询无法直接限制关联数据条数,结合PostgreSQL特性,以下是两种可行实现方式:
方式一:子查询筛选(简单场景)
通过子查询直接筛选每个用户的前5张照片(按ID倒序),并映射到用户的photos字段:
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, QueryBuilder } from 'typeorm'; import { User } from './user.entity'; import { Photo } from './photo.entity'; @Injectable() export class UserService { constructor( @InjectRepository(User) private userRepository: Repository<User>, ) {} async getUsersWithMax5Photos() { return this.userRepository .createQueryBuilder('user') .leftJoinAndMapMany( 'user.photos', // 要映射到的用户实体字段 (qb: QueryBuilder<Photo>) => { return qb .select('photo.*') .from(Photo, 'photo') .where('photo.userId = user.id') .orderBy('photo.id', 'DESC') .limit(5); }, 'photo', 'photo.userId = user.id' ) .getMany(); } }
方式二:窗口函数筛选(自定义排序场景)
如果需要按特定字段(如创建时间)排序后取前5张,可使用PostgreSQL的ROW_NUMBER()窗口函数:
async getUsersWithMax5Photos() { return this.userRepository .createQueryBuilder('user') .leftJoinAndMapMany( 'user.photos', (qb: QueryBuilder<Photo>) => { return qb .select(` photo.*, ROW_NUMBER() OVER (PARTITION BY photo.userId ORDER BY photo.createdAt DESC) AS rn `) .from(Photo, 'photo') .having('rn <= 5') .orderBy('rn'); }, 'photo', 'photo.userId = user.id' ) .getMany(); }
注意事项
- 必须确保
Photo实体中存在userId外键字段,否则关联查询会失败。 - 若需对用户进行分页查询,窗口函数方案不会干扰主查询的分页逻辑。
- 子查询方案在数据量较小时性能更优,窗口函数方案适合需要复杂排序规则的场景。
内容的提问来源于stack exchange,提问作者chirag thapa
相关产品推荐
相关产品推荐

