LoopBack4中为每个Exercise模型对象获取单条关联AthletExerciseLog记录的实现方案
解决LoopBack关联查询中每个父对象仅返回一条最新关联记录的问题
你遇到的问题很典型:当前的limit: 1是对整个关联查询结果集做全局限制,而不是按每个exerciseid分组后各取1条。生成的SQL最后加了LIMIT 1,所以只会返回符合条件的第一条记录,自然只会对应一个exercise。
下面提供几种可行的解决方案,你可以根据自己的场景选择:
方法1:使用子查询筛选每个Exercise的最新日志
通过子查询,为每个Exercise单独筛选出其对应的最新AthletExerciseLog记录,再关联到主查询中:
exerciseController.find({ include: [{ relation: "athletExerciseLogsExercise", scope: { where: { userId: id, id: { // 使用参数化查询避免SQL注入,同时关联当前Exercise的id inq: [ db.raw(` SELECT id FROM athletExerciseLog WHERE exerciseId = ? AND userId = ? ORDER BY date DESC LIMIT 1 `, [db.col('Exercise.id'), id]) ] } } } }] });
这种方式兼容性较好,大多数数据库都支持,而且能精准控制每个Exercise的最新记录。
方法2:使用窗口函数(ROW_NUMBER())分组取最新记录
利用数据库的窗口函数ROW_NUMBER(),按exerciseId分组并按date倒序排序,取每组的第一条记录:
exerciseController.find({ include: [{ relation: "athletExerciseLogsExercise", scope: { where: db.raw(` userId = ? AND ROW_NUMBER() OVER (PARTITION BY exerciseId ORDER BY date DESC) = 1 `, [id]) } }] });
窗口函数的性能通常比子查询更优,适合数据量较大的场景,不过要注意你的数据库是否支持窗口函数(比如PostgreSQL、MySQL 8.0+都支持)。
方法3:定义HasOne关联指向最新日志
如果你的业务经常需要获取每个Exercise的最新日志,可以直接在Exercise模型中定义一个hasOne关联,专门指向最新的那条记录:
export class Exercise extends Entity { ... @hasMany(() => AthletExerciseLog, {keyTo: 'exerciseId'}) athletExerciseLogsExercise?: AthletExerciseLog[]; // 新增hasOne关联,专门获取最新日志 @hasOne(() => AthletExerciseLog, { keyTo: 'exerciseId', scope: { order: ['date DESC'], limit: 1 } }) latestAthletExerciseLog?: AthletExerciseLog; ... }
查询时直接include这个新关联,并传入userId条件:
exerciseController.find({ include: [{ relation: "latestAthletExerciseLog", scope: { where: { userId: id } } }] });
这种方式代码更简洁,语义更清晰,适合频繁使用该查询的场景。
注意事项
- 无论用哪种方法,都要避免直接拼接字符串到SQL中,一定要用参数化查询(比如上面的
db.raw带参数的写法),防止SQL注入。 - 如果使用窗口函数,要确认你的数据库版本支持该特性(比如MySQL 5.x不支持窗口函数,需要升级到8.0+)。
内容的提问来源于stack exchange,提问作者el-niko
相关产品推荐
相关产品推荐

