如何使用Sequelize的findAll()将关联数据以数组形式返回?
我是Sequelize新手,学习查询格式化技巧时遇到问题。我有invoices和invoice_items两张表,二者为一对多关联(一个invoice对应多个invoice_items)。我希望用findAll()查询时,将invoice_items以数组形式嵌套在对应的invoice对象中,期望返回格式如下:
[ { name: 'invoice1', invoiceItems: [ 'itemOne', 'itemTwo', ] }, { name: 'invoice2', invoiceItems: [ 'itemOne', 'itemTwo', ] } ]
但我当前使用包含raw:true和nest:true的查询语句:
db.invoice.findAll({ where: { userId: req.user.id }, include: "invoiceItems", raw : true, nest : true });
得到的结果是每个关联项对应一个invoice对象:
[ { name: 'invoice1', invoiceItems: 'itemOne' }, { name: 'invoice1', invoiceItems: 'itemTwo' }, { name: 'invoice2', invoiceItems: 'itemOne' }, { name: 'invoice2', invoiceItems: 'itemTwo' } ]
请问是否有方法直接通过查询实现期望的格式?另外我后续通过get({plain:true})处理结果得到了目标格式,相关代码如下:
db.invoice.findAll({ where: { userId: req.user.id }, include: "invoiceItems", }).then(results => { let processedResults = []; for (result of results){ processedResults.push(result.get({ plain: true })); } return processedResults; });
解答
问题出在raw: true配置上:开启raw: true后,Sequelize会直接返回数据库JOIN查询的原始结果,而数据库的JOIN操作本来就是每行对应一个关联项,所以会出现重复的invoice对象,每个对象仅携带一个invoice_item。
要直接通过查询得到嵌套数组格式,有两种可行方式:
1. 去掉raw: true,利用Sequelize模型实例自动聚合关联数据
这是最符合Sequelize设计思路的方式,默认情况下findAll()返回模型实例,Sequelize会自动将一对多的关联数据聚合为数组。如果需要纯JSON对象,可以用map简化处理代码:
db.invoice.findAll({ where: { userId: req.user.id }, include: "invoiceItems", }).then(results => { return results.map(result => result.get({ plain: true })); });
2. (不推荐)手动聚合原始查询结果
如果一定要使用raw: true,可以手动遍历结果,根据invoice的唯一标识(比如id)分组,把对应的invoiceItems收集到数组中。示例代码如下:
db.invoice.findAll({ where: { userId: req.user.id }, include: "invoiceItems", raw: true, nest: true }).then(rawResults => { const grouped = {}; rawResults.forEach(item => { const invoiceId = item.id; if (!grouped[invoiceId]) { grouped[invoiceId] = { ...item, invoiceItems: [] }; } grouped[invoiceId].invoiceItems.push(item.invoiceItems); }); return Object.values(grouped); });
这种方式需要自行处理分组逻辑,不如第一种方法省心,仅适合特殊场景使用。
总结:涉及关联嵌套格式时,优先使用Sequelize模型实例+get({plain: true})的方式,避免raw: true带来的额外处理成本。
内容的提问来源于stack exchange,提问作者Brenden

