jsonb对象数组和列的合并困难

Tar*_*len 1 sql postgresql json jsonb

我有一张桌子

Visitor: (id, signup_up, sessions, email, custom_fields)

custom_fields表单的JSON对象的jsonb数组在哪里

CustomField: ( field, value ) 例: (domain, www.somedomain.com)

我想获取signed_up, sessions, email列和它们的值,以及数组中的CustomFieldjson对象custom_fields,并将它们合并到data使用相同CustomField结构调用的第3个字段中,即.每个条目都有表格field: value.

鉴于这些行

id | sessions | email              | custom_fields
---------------------------------------------------------------
1  | 3        | test@gmail.com      [{ field: domain, value: "www.hello.com" }, { field: type, value: "Customer" }]
---------------------------------------------------------------
2  | 5        | another@gmail.com   [{ field: domain, value: "www.other.com" }, { field: type, value: "Customer" }]
Run Code Online (Sandbox Code Playgroud)

我想得到

id | fields
-----------------------
1  | [{sessions: 3, email: test@gmail.com, domain: "www.hello.com", type: "Customer"}]
----------------------
2  | [{sessions: 5, email: another@gmail.com, domain: "www.other.com", type: "Customer"}]
Run Code Online (Sandbox Code Playgroud)

有关如何实现这一点的任何想法?

任何帮助深表感谢

kli*_*lin 6

示例数据(这应该是问题的一部分,而不是答案;请注意正确的json语法):

create table visitor (id int, sessions int, email text, custom_fields jsonb);
insert into visitor values
(1, 3, 'test@gmail.com', '[{"field": "domain", "value": "www.hello.com" }, {"field": "type", "value": "Customer"}]'),
(2, 5, 'another@gmail.com', '[{"field": "domain", "value": "www.other.com" }, {"field": "type", "value": "Customer"}]');
Run Code Online (Sandbox Code Playgroud)

提示1.使用jsonb_array_elements()和选择的JSON值fieldvaluekeyvalue:

select id, sessions, email, elem->>'field' as key, elem->>'value' as value
from visitor, jsonb_array_elements(custom_fields) elem;

 id | sessions |       email       |  key   |     value     
----+----------+-------------------+--------+---------------
  1 |        3 | test@gmail.com    | domain | www.hello.com
  1 |        3 | test@gmail.com    | type   | Customer
  2 |        5 | another@gmail.com | domain | www.other.com
  2 |        5 | another@gmail.com | type   | Customer
(4 rows)
Run Code Online (Sandbox Code Playgroud)

提示2.用于jsonb_object_agg()将这些pair(key, value)聚合到json对象中:

select 
    id, 
    jsonb_object_agg(key, value)
from (
    select id, sessions, email, elem->>'field' as key, elem->>'value' as value
    from visitor, jsonb_array_elements(custom_fields) elem
    ) s
group by id, sessions, email
order by id;

 id |                jsonb_object_agg                 
----+-------------------------------------------------
  1 | {"type": "Customer", "domain": "www.hello.com"}
  2 | {"type": "Customer", "domain": "www.other.com"}
(2 rows)
Run Code Online (Sandbox Code Playgroud)

最终查询.从添加内置列(串连)JSON对象sessionemail,并建立与所有对象JSON数组:

select 
    id, 
    json_build_array(
        jsonb_object_agg(key, value) ||
        jsonb_build_object('sessions', sessions, 'email', email)
        ) as fields
from (
    select id, sessions, email, elem->>'field' as key, elem->>'value' as value
    from visitor, jsonb_array_elements(custom_fields) elem
    ) s
group by id, sessions, email
order by id;

 id |                                             fields                                             
----+------------------------------------------------------------------------------------------------
  1 | [{"type": "Customer", "email": "test@gmail.com", "domain": "www.hello.com", "sessions": 3}]
  2 | [{"type": "Customer", "email": "another@gmail.com", "domain": "www.other.com", "sessions": 5}]
(2 rows)
Run Code Online (Sandbox Code Playgroud)

还有一个提示(或技巧):

select '{"a": null}'::jsonb || '{"a": 1}'::jsonb;

 ?column? 
----------
 {"a": 1}
(1 row) 
Run Code Online (Sandbox Code Playgroud)