PostgreSQL jsonb如何为嵌套json对象新增键值对且不生成独立元素
问题根因
你之前写的SQL逻辑偏差主要在两处:
- 拼接操作的对象层级不对:
json_col->'json_col'取到的是整个数组结构,把数组和独立json对象做||拼接时,jsonb的原生逻辑是给数组追加新元素,自然就生成了数组内的第二个独立对象,完全没有修改数组内部原有的第一个对象内容。 jsonb_set的替换路径没有下沉到数组内部的具体元素节点,相当于直接把整个json_col键的值替换成了拼接后的数组结果,没有精准命中要修改的子节点。
这里需要注意jsonb的原生拼接规则:两个json对象做
||操作时,会完成同层级键值的合并;只要拼接的操作数中包含数组,非数组的操作数就会被作为新元素追加到数组末尾,这也是你之前生成双对象结果的核心原因。
可实现需求的正确写法
方案一:用jsonb_set精准定位修改
通过调整jsonb_set的目标路径,直接定位到数组的第0个元素,做对象级的键值合并:
UPDATE table SET json_col = jsonb_set( json_col, -- 路径层级:根节点下的json_col键 -> 数组索引为0的元素 '{json_col,0}', -- 取数组第0位的原有对象,和新增键值做对象合并 (json_col -> 'json_col' -> 0) || '{"test":123}'::jsonb ) where id=6400;
核心调整点:
- 把原来直接替换
json_col键值的路径,改成延伸到数组的0号索引位置,让替换动作发生在数组内部的对象层级 - 拼接的两个值都是json对象时,jsonb会自动将双方的键值合并到同一个对象中,不会新增数组元素
方案二:直接重建目标层级结构
如果觉得jsonb_set的路径逻辑容易写错,也可以用构造函数直接拼出符合要求的json结构,逻辑更直观:
UPDATE table SET json_col = jsonb_build_object( 'json_col', jsonb_build_array( -- 保持数组只有1个元素,该元素为原有对象合并新键值后的结果 (json_col -> 'json_col' -> 0) || '{"test":123}'::jsonb ) ) where id=6400;
执行后效果
两种写法执行完,都会输出目标结构:
{ "json_col": [ { "val1": 1, "val2": 0, "val3": "qwe", "test": 123 } ] }
内容的提问来源于stack exchange,提问作者Алексей
相关产品推荐
相关产品推荐

