Sequelize聚合函数在GraphQL中返回count值为null的问题排查
根据你描述的情况——SQL在psql执行正常、res.rows里有正确的count字符串值,但GraphQL返回count为null,核心问题基本集中在字段映射不匹配或类型兼容问题上,下面是具体的排查和解决步骤:
1. 确保Sequelize查询的聚合字段有正确别名
GraphQL是严格按照字段名匹配返回结果的,如果你的Counts类型定义里的count字段是count,那Sequelize查询时必须给聚合函数指定同名别名,否则返回的字段名会是count(*)这类默认值,GraphQL找不到对应字段就会返回null。
举个正确的查询示例:
const { rows } = await Booking.findAndCountAll({ attributes: [ 'section', // 给聚合结果指定别名'count',和GraphQL类型的字段名一致 [sequelize.fn('count', sequelize.col('id')), 'count'] ], group: ['section'], raw: true // 开启raw模式,直接返回扁平化的普通对象,避免Model实例的嵌套结构 });
2. 把字符串类型的count转为数字类型
你提到res.rows里的count是字符串值,而如果你的GraphQL Counts类型中count定义的是Int(或Float)类型,GraphQL会因为类型不兼容自动返回null。这时候需要在Resolver里手动转换类型:
// 在Resolver中处理查询结果,将count转为数字 const formattedResults = rows.map(item => ({ section: item.section, count: parseInt(item.count, 10) // 或者用Number(item.count),根据实际情况选择 })); return formattedResults;
为什么count会是字符串?PostgreSQL在返回聚合函数结果时,某些场景下会以字符串形式返回,尤其是未显式指定类型转换时,手动转类型就能解决这个问题。
3. 确认正确提取Model实例中的数据
如果你没有开启raw: true,Sequelize返回的是Model实例对象,实际字段值会嵌套在dataValues属性里,直接访问item.count会拿到undefined或Model的方法,导致GraphQL返回null。这种情况下要修改数据提取方式:
// 未开启raw模式时的处理方式 const formattedResults = rows.map(item => ({ section: item.dataValues.section, count: parseInt(item.dataValues.count, 10) }));
4. 验证查询结果的结构
可以在Resolver里打印完整的rows结构,确认字段名和值的类型是否符合预期:
console.log(JSON.stringify(rows, null, 2));
如果输出的字段名是count(*),那就是别名问题;如果count值是字符串,那就是类型转换问题,对应调整即可。
内容的提问来源于stack exchange,提问作者James David Bradly Carballo

