如何在Sequelize中仅获取关联记录ID而非全量关联数据?
解决Sequelize批量获取关联记录ID数组的问题
需求与遇到的问题
不想预加载全部关联数据(大部分用不上),只需要拿到关联记录的ID数组——用来判断有没有关联数据,或者做跳转用。想搞个通用的抽象方法,不用给每个关联关系都写单独的函数。
已经定义了Item和Stock模型,是一对多关系:ItemModel.hasMany(StockModel),StockModel.belongsTo(ItemModel),Stocks表里已经自动生成了ItemId字段。
之前试了用attributes加include的方式搞计算属性,但碰到俩问题:
- 第一次写的代码直接报错,错误栈指向PostgreSQL的查询模块,但没明确原因
- 不知道怎么在子查询里引用当前Item记录的
id,没法关联到对应的Stock数据
后来修正了PostgreSQL的查询语句,报错是没了,但还是没法关联当前记录的ID,查出来的是所有Stock的ID,不是当前Item对应的。
期望的输出格式是这样的:
[{ id: 1, name: "Ice Cream", StocksIds: [1,3,54,127] }]
正确实现代码
要让子查询关联到当前Item的ID,同时用聚合函数把ID拼成字符串,后续转成数组就行,代码如下:
const relatedModel = 'Stocks'; const records = await ItemModel.findAll({ attributes: { include: [ [ sequelize.literal(`( SELECT STRING_AGG(CAST(id AS VARCHAR), ',') FROM "${relatedModel}" WHERE "${relatedModel}"."ItemId" = "Item"."id" )`), `${relatedModel}Ids` ] ] }, raw: true // 可选,要原始数据格式的话加这个,方便后续转数组 }); // 可选步骤:把逗号分隔的字符串转成数字数组 const formattedRecords = records.map(item => ({ ...item, StocksIds: item.StocksIds ? item.StocksIds.split(',').map(Number) : [] }));
关键要点
- 关联当前记录ID:子查询里通过
"${relatedModel}"."ItemId" = "Item"."id"绑定当前Item的ID,这样每个Item只会拿到自己关联的Stock ID - 聚合函数处理:用
STRING_AGG把多个ID拼成逗号分隔的字符串,避免子查询返回多行结果,导致主查询出错 - 格式转换:如果需要数组格式,用
split拆分字符串,再转成数字就行;如果数据库返回的是空值,要处理成空数组避免报错 - 引号注意事项:PostgreSQL里区分大小写的表名/字段名必须用双引号包裹,要和你Sequelize里定义的一致,不然会找不到表或字段
之前的错误原因
- 第一次报错是因为子查询没关联主表,也没加聚合函数,子查询返回了所有Stock的ID(多行),和主查询的单行Item记录不匹配,数据库直接报错
- 没法关联当前记录ID是因为子查询里没引用主表的
"Item"."id",导致子查询查的是全表数据,不是当前Item对应的Stock
内容的提问来源于stack exchange,提问作者Randy Hall
相关产品推荐
相关产品推荐

