Postgres 函数将两个具有重叠键的 json 对象合并为一个对象
Postgres function to merge two json objects with overlapping keys into one object
我有以下 json 对象:
{
"a" : {
"0" : 2,
"1" : 4,
"3" : 6,
}
"b" : {
"2" : 8,
"1" : 10, /*note this key exists in "a" too*/
"4" : 12,
}
}
我想生成以下对象,然后能够像这样从中提取元素:
{
"0" : 2,
"1" : 10,
"2" : 8,
"3" : 6,
"4" : 12,
}
提取:object->>'1'
应该return'10'
基本上我有两个数组,它们的键可能重叠,我想合并这两个数组,让一个数组优先。
我怎样才能做到这一点?理想情况下,我会调用 arrayMerge(a, b)
之类的函数,它给予 'a'
比 'b'
更高的优先级
答案涉及 Postgres 9.4 和 9.3。
示例数据:
create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');
首先,检索具有任意选择优先级的所有对:
select 0 priority, jsonb_each(val->'b') elem
from test_js
union all
select 1 priority, jsonb_each(val->'a') elem
from test_js
order by 1
priority | elem
----------+--------
0 | (1,10)
0 | (2,8)
0 | (4,12)
1 | (0,2)
1 | (1,4)
1 | (3,6)
(6 rows)
接下来,来自结果集 select 个具有唯一键的元素:
select distinct on ((elem).key) elem
from (
select 0 priority, jsonb_each(val->'b') elem
from test_js
union all
select 1 priority, jsonb_each(val->'a') elem
from test_js
) sub
elem
--------
(0,2)
(1,10)
(2,8)
(3,6)
(4,12)
(5 rows)
最后,将结果聚合成一个json对象:
select json_object_agg((elem).key, (elem).value) result
from (
select distinct on ((elem).key) elem
from (
select 0, jsonb_each(val->'b') elem
from test_js
union all
select 1, jsonb_each(val->'a') elem
from test_js
) sub
) sub
result
---------------------------------------------------
{ "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)
在 Postgres 9.3 中,您可以使用 string_agg
:
模拟 json_object_agg
select format('{ %s }',
string_agg(format('"%s" : %s', (elem).key, (elem).value), ', '))::json result
from (
select distinct on ((elem).key) elem
from (
select 0, json_each(val->'b') elem
from test_js
union all
select 1, json_each(val->'a') elem
from test_js
) sub
) sub
result
---------------------------------------------------
{ "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)
顺便说一句,您的 json 值无效,应该是
{
"a": {
"0": 2,
"1": 4,
"3": 6
},
"b": {
"1": 10,
"2": 8,
"4": 12
}
}
请使用 JSONLint 验证 json 值。
在 Postgres 9.5+ 中,您可以简单地使用内置的连接运算符 ||
来合并 JSON 个对象。
create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');
select (val->'a') || (val->'b') from test_js;
?column?
--------------------------------------------
{"0": 2, "1": 10, "2": 8, "3": 6, "4": 12}
(1 row)
我有以下 json 对象:
{
"a" : {
"0" : 2,
"1" : 4,
"3" : 6,
}
"b" : {
"2" : 8,
"1" : 10, /*note this key exists in "a" too*/
"4" : 12,
}
}
我想生成以下对象,然后能够像这样从中提取元素:
{
"0" : 2,
"1" : 10,
"2" : 8,
"3" : 6,
"4" : 12,
}
提取:object->>'1'
应该return'10'
基本上我有两个数组,它们的键可能重叠,我想合并这两个数组,让一个数组优先。
我怎样才能做到这一点?理想情况下,我会调用 arrayMerge(a, b)
之类的函数,它给予 'a'
比 'b'
答案涉及 Postgres 9.4 和 9.3。
示例数据:
create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');
首先,检索具有任意选择优先级的所有对:
select 0 priority, jsonb_each(val->'b') elem
from test_js
union all
select 1 priority, jsonb_each(val->'a') elem
from test_js
order by 1
priority | elem
----------+--------
0 | (1,10)
0 | (2,8)
0 | (4,12)
1 | (0,2)
1 | (1,4)
1 | (3,6)
(6 rows)
接下来,来自结果集 select 个具有唯一键的元素:
select distinct on ((elem).key) elem
from (
select 0 priority, jsonb_each(val->'b') elem
from test_js
union all
select 1 priority, jsonb_each(val->'a') elem
from test_js
) sub
elem
--------
(0,2)
(1,10)
(2,8)
(3,6)
(4,12)
(5 rows)
最后,将结果聚合成一个json对象:
select json_object_agg((elem).key, (elem).value) result
from (
select distinct on ((elem).key) elem
from (
select 0, jsonb_each(val->'b') elem
from test_js
union all
select 1, jsonb_each(val->'a') elem
from test_js
) sub
) sub
result
---------------------------------------------------
{ "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)
在 Postgres 9.3 中,您可以使用 string_agg
:
json_object_agg
select format('{ %s }',
string_agg(format('"%s" : %s', (elem).key, (elem).value), ', '))::json result
from (
select distinct on ((elem).key) elem
from (
select 0, json_each(val->'b') elem
from test_js
union all
select 1, json_each(val->'a') elem
from test_js
) sub
) sub
result
---------------------------------------------------
{ "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)
顺便说一句,您的 json 值无效,应该是
{
"a": {
"0": 2,
"1": 4,
"3": 6
},
"b": {
"1": 10,
"2": 8,
"4": 12
}
}
请使用 JSONLint 验证 json 值。
在 Postgres 9.5+ 中,您可以简单地使用内置的连接运算符 ||
来合并 JSON 个对象。
create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');
select (val->'a') || (val->'b') from test_js;
?column?
--------------------------------------------
{"0": 2, "1": 10, "2": 8, "3": 6, "4": 12}
(1 row)