应使用jsonb_agg或jsonb_object_agg聚合jsonb数据:前者生成数组,后者生成对象;二者均保持原始结构、类型及null语义,避免string_agg等文本拼接导致的解析失效与类型丢失。

直接用 jsonb_agg 或 jsonb_object_agg,别试图先转成 text 再拼接——会丢结构、类型、null 语义,且无法反向解析。
聚合 JSONB 数组:用 jsonb_agg,不是 string_agg
想把多行 JSONB 字段合并成一个 JSON 数组,必须用 jsonb_agg。它保持每个元素的原始 JSONB 类型和嵌套结构;而 string_agg 只输出字符串,再 cast 回 JSONB 会破坏引号、转义和 null 表示。
-
jsonb_agg(info)正确:结果是[{"name":"张三"}, {"name":"李四"}](合法 JSONB 数组) -
string_agg(info::text, ',')错误:结果是{"name":"张三"},{"name":"李四"}(非法 JSON,缺外层[]) - 空输入时
jsonb_agg返回NULL,不是空数组[];需要空数组请补COALESCE(jsonb_agg(...), '[]'::jsonb) - 若被聚合字段本身为
NULL,该行会被跳过(符合 SQL 聚合惯例),不会插入null元素
按 key-value 聚合成 JSONB 对象:用 jsonb_object_agg
当有两列(如 key_col 和 val_col),想构造成 {"k1": "v1", "k2": "v2"} 这样的对象,jsonb_object_agg(key_col, val_col) 是唯一可靠方式。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 键必须是
text类型,非 text 会隐式 cast,但失败时直接报错(如int为NULL就炸) - 值可以是任意类型,自动转为 JSONB 表示:数值不变,
NULL变成 JSONnull,布尔变true/false - 重复 key 会保留最后一条,不报错也不警告
- 不要用
jsonb_build_object替代——它只接受固定参数个数,不能动态聚合多行
WHERE 或 GROUP BY 中过滤 JSONB 字段后再聚合,索引能生效
高频场景:统计满足某个 JSONB 条件的记录数,或聚合其字段。只要条件写法得当,GIN 索引可命中。
- 推荐写法:
WHERE info @> '{"status":"active"}'—— 使用@>操作符,配合jsonb_path_ops或jsonb_opsGIN 索引 - 避免写法:
WHERE info->>'status' = 'active'—— 即使加了表达式索引,也常因类型转换或函数不可下推失效 - 聚合前加
filter (where ...)更清晰:jsonb_agg(info) FILTER (WHERE info @> '{"type":"user"}') - 如果聚合后还要查嵌套字段(如
jsonb_agg(...) #>> '{0,items,0,name}'),别指望索引加速——那是运行时计算
聚合结果再提取字段?小心嵌套层级和类型转换
jsonb_agg 输出是数组,jsonb_object_agg 输出是对象,后续用 -> / ->> 提取时,必须匹配结构。
- 从聚合数组取第一个元素:
(jsonb_agg(info))->0—— 注意括号,否则运算符优先级导致错误 - 提取后仍是 JSONB 类型,要文本值得再套
->>:((jsonb_agg(info))->0)->>'name' - 如果不确定数组长度,用
jsonb_path_query_first更安全:jsonb_path_query_first(jsonb_agg(info), '$[0].name') - 对空结果集聚合(如
WHERE false),jsonb_agg返回NULL,直接->会得NULL,不是错误——但->>对NULL输入返回字符串'null',WHERE 里易误判
最常被忽略的是聚合后的类型延续性:你拿到的永远是 JSONB,不是普通字段。所有后续操作都得按 JSONB 规则走,不能当成 text 或 varchar 去 LIKE 或 || 拼接,否则语义全乱。










