TypeORM左连接一对多关联结果如何限制排序并映射为单个字段
TypeORM 一对多关联分组限制条数查询实现方案
你可以直接通过TypeORM QueryBuilder实现需求,也可以选择手动处理数据,两种方案各有适用场景,具体实现如下:
前提优化提示
你当前的Activity模型中@OneToMany装饰器下的@JoinColumn是冗余配置,@JoinColumn仅需要在@ManyToOne侧声明即可,可直接删除避免不必要的异常。
方案1:单QueryBuilder实现(推荐,性能更优)
借助数据库窗口函数ROW_NUMBER实现每个活动下最新3名参与人的过滤,直接通过TypeORM映射返回你需要的结构,无需手动拼接:
const result = await activityRep .createQueryBuilder('a') // 子查询给每个活动的参与人按加入时间倒序排名 .leftJoin( (qb) => qb .select('*') .addSelect( 'ROW_NUMBER() OVER (PARTITION BY activity_id ORDER BY createdAt DESC)', 'rn' ) .from(ActivitiyAttendant, 'aj'), 'aj_filter', 'aj_filter.activity_id = a.activity_id AND aj_filter.rn <= 3' ) // 把过滤后的参与人映射到自定义字段recent_attendants .leftJoinAndMapMany( 'a.recent_attendants', ActivitiyAttendant, 'aj', 'aj.activity_attendant_id = aj_filter.activity_attendant_id' ) // 指定返回字段 .select([ 'a.activity_id', 'a.title', 'aj.activity_attendant_id', 'aj.profile_picture', ]) .getMany();
该方案仅执行一次SQL查询,性能最优,支持MySQL 8.0+、PostgreSQL、SQL Server等支持窗口函数的数据库,返回的result结构完全符合你给出的期望格式。
方案2:手动拼接实现(兼容性好)
如果你的数据库不支持窗口函数(如MySQL 5.7及更低版本),可以通过两次查询+手动组装的方式实现,写法更简单易维护:
// 1. 查询所有活动基础信息 const activities = await activityRep.find({ select: ['activity_id', 'title'], }); if (!activities.length) return []; // 2. 查询所有关联的参与人,按加入时间倒序 const activityIds = activities.map((item) => item.activity_id); const allAttendants = await attendantRep .createQueryBuilder('aj') .select(['aj.activity_id', 'aj.activity_attendant_id', 'aj.profile_picture']) .where('aj.activity_id IN (:...activityIds)', { activityIds }) .orderBy('aj.createdAt', 'DESC') .getMany(); // 3. 按活动分组,每个活动仅保留前3名参与人 const attendantGroup = new Map(); allAttendants.forEach((item) => { if (!attendantGroup.has(item.activity_id)) { attendantGroup.set(item.activity_id, []); } const list = attendantGroup.get(item.activity_id); if (list.length < 3) { list.push({ activity_attendant_id: item.activity_attendant_id, profile_picture: item.profile_picture, }); } }); // 4. 组装最终结果 const result = activities.map((item) => ({ ...item, recent_attendants: attendantGroup.get(item.activity_id) || [], }));
内容的提问来源于stack exchange,提问作者Azad Mamun
相关产品推荐
相关产品推荐

