You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Sequelize的findAll()将关联数据以数组形式返回?

Sequelize一对多关联查询格式化问题

我是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 15:15:00