如何让Sequelize findAll内连接后返回重复的表A行JSON结果?
问题描述
需要通过Sequelize的findAll方法实现:返回的JSON结果中,根据表B(Message)的匹配项,重复返回表A(Conversation)的行,每行仅包含一个关联的Message。
当前代码:
await this._conversation.findAll({ include: [ { required: true, model: Message, as: 'messages', where: message_query, }, ], })
当前返回结果:
[ { // Conversation [ table A ] .... "messages": [ { // message 1 [ table B ] .... }, { // message 2 [ table B ] .... }, { // message 3 [ table B ] .... }, ] } ]
期望返回结果:
[ { // Conversation [ table A ] .... "messages": [ { // message 1 [ table B ] .... }, ] }, { // Conversation [ table A ] .... "messages": [ { // message 2 [ table B ] .... }, ] }, { // Conversation [ table A ] .... "messages": [ { // message 3 [ table B ] .... }, ] }, ]
原生SQL查询能得到目标结果:
SELECT * FROM `conversations` INNER JOIN `messages` ON `conversations`.`id` = `messages`.`conversation_id`
解决方案
Sequelize默认会将同一父模型(Conversation)的关联子模型(Message)聚合到数组中,要实现原生SQL的效果,需要手动调整查询或转换结果结构。
方法一:使用raw+nest查询后手动转换
通过raw: true获取原生SQL返回的平级数据,再将结构转换为期望的格式:
// 执行查询,获取平级的关联数据 const rawResults = await this._conversation.findAll({ include: [ { required: true, model: Message, as: 'messages', where: message_query, }, ], raw: true, nest: true // 嵌套关联字段,避免字段名冲突 }); // 转换为期望的结构 const formattedResults = rawResults.map(item => { const conversation = {}; const singleMessage = {}; // 拆分Conversation和Message的字段 Object.keys(item).forEach(key => { if (key.startsWith('messages.')) { singleMessage[key.replace('messages.', '')] = item[key]; } else { conversation[key] = item[key]; } }); return { ...conversation, messages: [singleMessage] }; });
方法二:从Message模型反向查询并转换结构
如果Message和Conversation已建立反向关联(Message属于Conversation),可以直接查询Message,再将结构反转:
// 假设Message模型中关联Conversation的别名为`conversation` const messages = await Message.findAll({ include: [ { required: true, model: Conversation, as: 'conversation' } ], where: message_query }); // 转换为目标结构 const formattedResults = messages.map(msg => { // 转换为JSON对象(如果是Sequelize实例的话) const convData = msg.conversation.toJSON ? msg.conversation.toJSON() : msg.conversation; const msgData = msg.toJSON ? msg.toJSON() : msg; // 删除Message中的conversation字段,避免冗余 delete msgData.conversation; return { ...convData, messages: [msgData] }; });
内容的提问来源于stack exchange,提问作者yeln
相关产品推荐
相关产品推荐

