json_arrayagg是mysql 8.0+聚合函数,必须配合group by使用,将分组内多行聚合成一个json数组;不加group by则默认全表聚合为单行结果,且order by需置于函数内部才生效。

JSON_ARRAYAGG 会把多行结果聚合成一个 JSON 数组
它不是格式化工具,而是聚合函数——必须配合 GROUP BY 使用,否则默认对全部行做聚合,只返回一行结果。如果你查 100 条用户记录却想得到 100 个独立 JSON 对象,JSON_ARRAYAGG 不是那个工具;它适合“把某个分组下的所有子项打包成数组”这种场景,比如查每个部门的员工列表。
必须搭配 GROUP BY,否则容易误得单元素数组
常见错误是写成这样:
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id, 'name', name)) FROM users;
这会把整张表所有用户塞进一个大数组里,哪怕你只想查 3 个用户也返回 [{...},{...},{...}] ——看起来对,但一旦加了 WHERE 或连接其他表,逻辑就容易失控。真正可控的做法是明确分组维度:
- 按业务主键分组(如
GROUP BY dept_id),让每个部门生成自己的员工数组 - 若确实只需一个全局数组,至少显式加
GROUP BY ()(MySQL 8.0.23+ 支持),避免隐式行为差异 - PostgreSQL 没有
JSON_ARRAYAGG,得用json_agg(),函数名和参数顺序都不同
嵌套 JSON_OBJECT 时字段别名决定 key 名,NULL 处理要主动控制
JSON_OBJECT 里用的别名就是最终 JSON 的 key,比如 JSON_OBJECT('user_id', u.id) 输出 {"user_id": 123}。更关键的是:任意字段为 NULL 时,整个 JSON_OBJECT 默认跳过该键值对——不是输出 "key": null,而是直接消失。如果需要保留空字段,得手动补:
JSON_OBJECT('id', COALESCE(u.id, 0), 'name', COALESCE(u.name, ''))
另外,MySQL 8.0.17+ 支持 JSON_OBJECTAGG(key, value) 做键值对聚合,和 JSON_ARRAYAGG(JSON_OBJECT(...)) 是不同路径,别混用。
ORDER BY 在 JSON_ARRAYAGG 内部才生效,外部排序无效
这个最容易踩坑:以下写法不会影响数组内元素顺序:
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id)) FROM users ORDER BY id;
正确方式是把 ORDER BY 放进聚合函数内部:
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id) ORDER BY id) FROM users;
而且注意:MySQL 中 ORDER BY 必须在 JSON_OBJECT 之后、括号闭合前;PostgreSQL 的 json_agg() 则要求 ORDER BY 紧跟在函数名后,语法位置不兼容。跨数据库迁移时这里大概率报错。
数组长度没上限,但超大结果可能触发 group_concat_max_len 或内存限制,线上用之前最好在小数据集上试下实际体积。











