JSON_ARRAYAGG会保留NULL值为数组元素,需用WHERE或IFNULL过滤;必须配合GROUP BY实现分组聚合,否则全表聚合为单行;嵌套应使用JSON函数而非CONCAT拼接;大数据量下受group_concat_max_len限制,需调高阈值。

JSON_ARRAYAGG 会自动把 NULL 值变成数组里的 null 元素
如果你的字段里有 NULL,JSON_ARRAYAGG 不会跳过它,而是生成 [null, {"id": 1}, null] 这样的结果。这在前端解析时容易出错,尤其当你期望数组里全是对象。
常见做法是用 WHERE 过滤掉空值,或者用 IFNULL / COALESCE 替换:
SELECT JSON_ARRAYAGG(
JSON_OBJECT('id', id, 'name', name)
) FROM users WHERE id IS NOT NULL AND name IS NOT NULL;
如果必须保留行但不想让 NULL 进数组,得先转换——比如用 IF(id IS NULL, NULL, JSON_OBJECT(...)) 再配合 WHERE ... IS NOT NULL 二次过滤。
JSON_ARRAYAGG 必须配合 GROUP BY,否则默认聚合成一行
单独写 SELECT JSON_ARRAYAGG(json_col) FROM table 是合法的,但它把整张表所有行压成一个数组。多数时候你其实想按某个维度分组聚合,比如“每个 category 对应一个 JSON 数组”。
这时候漏写 GROUP BY 就会得到意外的单条结果,而不是你预期的多行分组结果:
- 要分组:加
GROUP BY category,每组返回一行,JSON_ARRAYAGG聚合该组内所有记录 - 不分组:全表聚合为一条记录,
JSON_ARRAYAGG返回一个大数组 - 没加
GROUP BY却在 SELECT 里混用了普通列(如SELECT category, JSON_ARRAYAGG(...)),MySQL 8.0+ 会报错Expression #1 of SELECT list is not in GROUP BY clause
嵌套 JSON_OBJECT 和 JSON_ARRAYAGG 容易引号逃逸混乱
手拼 JSON 字符串(比如用 CONCAT('{"items":', JSON_ARRAYAGG(...), '}'))非常危险:内部 JSON 的双引号不会被自动转义,最终得到非法 JSON。
正确方式永远优先用 JSON 函数组合:
SELECT JSON_OBJECT(
'category', category,
'items', JSON_ARRAYAGG(JSON_OBJECT('id', id, 'title', title))
)
FROM posts
GROUP BY category;
这样 MySQL 自动处理嵌套结构和引号转义。一旦看到 CONCAT + JSON_ARRAYAGG 混用,基本可以判定输出不可靠。
大数据量下 JSON_ARRAYAGG 可能触发 group_concat_max_len 截断
JSON_ARRAYAGG 底层复用 group_concat 的缓冲机制,受系统变量 group_concat_max_len 限制。默认值通常是 1024,远不够存多个 JSON 对象。
查当前值:SELECT @@group_concat_max_len;
临时调高(当前会话):SET SESSION group_concat_max_len = 1000000;
注意:这个设置只对当前连接生效;如果用连接池,得在每次获取连接后执行 SET,或直接改全局配置(需权限)。
另外,超长 JSON 不仅可能被截断,还会显著拖慢查询——建议在应用层分页聚合,而不是一次拉几十万条进一个 JSON 数组。


















