使用||运算符将产生以下结果:
||
select '{"a":{"b":2}}'::jsonb || '{"a":{"c":3}}'::jsonb ; ?column? ----------------- {"a": {"c": 3}} (1 row)
我希望能够实现以下结果(??对于操作员来说只是一个占位符):
??
select '{"a":{"b":2}}'::jsonb ?? '{"a":{"c":3}}'::jsonb ; ?column? ----------------- {"a": {"b": 2, "c": 3}} (1 row)
因此,您可以看到顶级a键的子值已“合并”,使得结果包含b和c。
a
b
c
如何在Postgres中“深度”合并两个 JSONB 值?
如果可能的话,这可能吗?
一个更复杂的测试用例:
select '{"a":{"b":{"c":3},"z":true}}'::jsonb ?? '{"a":{"b":{"d":4},"z":false}}'::jsonb ; ?column? ----------------- {"a": {"b": {"c": 3, "d": 4}, "z": false}} (1 row)
原始“合并”并成为对象的另一个测试用例:
select '{"a":{"b":{"c":3},"z":true}}'::jsonb ?? '{"a":{"b":false,"z":false}}'::jsonb ; ?column? ----------------- {"a": {"b": false, "z": false}} (1 row)
您应该合并jsonb_each()两个值都使用的未嵌套元素。在不平凡的查询中执行此操作可能会感到不舒服,因此我更喜欢这样的自定义函数:
jsonb_each()
create or replace function jsonb_my_merge(a jsonb, b jsonb) returns jsonb language sql as $$ select jsonb_object_agg( coalesce(ka, kb), case when va isnull then vb when vb isnull then va else va || vb end ) from jsonb_each(a) e1(ka, va) full join jsonb_each(b) e2(kb, vb) on ka = kb $$;
用:
select jsonb_my_merge( '{"a":{"b":2}, "d": {"e": 10}, "x": 1}'::jsonb, '{"a":{"c":3}, "d": {"f": 11}, "y": 2}'::jsonb ) jsonb_my_merge ------------------------------------------------------------------ {"a": {"b": 2, "c": 3}, "d": {"e": 10, "f": 11}, "x": 1, "y": 2} (1 row)
您可以使用递归稍微修改函数,以使解决方案可以在任何嵌套级别上使用:
create or replace function jsonb_recursive_merge(a jsonb, b jsonb) returns jsonb language sql as $$ select jsonb_object_agg( coalesce(ka, kb), case when va isnull then vb when vb isnull then va when jsonb_typeof(va) <> 'object' then va || vb else jsonb_recursive_merge(va, vb) end ) from jsonb_each(a) e1(ka, va) full join jsonb_each(b) e2(kb, vb) on ka = kb $$;
例子:
select jsonb_recursive_merge( '{"a":{"b":{"c":3},"x":5}}'::jsonb, '{"a":{"b":{"d":4},"y":6}}'::jsonb); jsonb_recursive_merge ------------------------------------------------ {"a": {"b": {"c": 3, "d": 4}, "x": 5, "y": 6}} (1 row) select jsonb_recursive_merge( '{"a":{"b":{"c":{"d":{"e":1}}}}}'::jsonb, '{"a":{"b":{"c":{"d":{"f":2}}}}}'::jsonb) jsonb_recursive_merge ---------------------------------------------- {"a": {"b": {"c": {"d": {"e": 1, "f": 2}}}}} (1 row)
最后,OP建议的功能变化形式(请参阅以下注释):
create or replace function jsonb_recursive_merge(a jsonb, b jsonb) returns jsonb language sql as $$ select jsonb_object_agg( coalesce(ka, kb), case when va isnull then vb when vb isnull then va when jsonb_typeof(va) <> 'object' or jsonb_typeof(vb) <> 'object' then vb else jsonb_recursive_merge(va, vb) end ) from jsonb_each(a) e1(ka, va) full join jsonb_each(b) e2(kb, vb) on ka = kb $$;