recursively flatten a nested jsonb in postgres without unknown depth and unknown key fields

前端 未结 1 1827
傲寒
傲寒 2021-01-02 22:52

How can I recursively flatten a nested jsonb in postgres which I don\'t know the depth and the field at each depth? (see example below)

A postgressql query to do the

相关标签:
1条回答
  • 2021-01-02 23:21

    Example setup:

    create table my_table(id int, data jsonb);
    insert into my_table values
    (1,
    $${
       "type": "a type",
       "form": "a form",
       "contact": {
           "name": "a name",
           "phone": "123-456-78",
           "type": "contact type",
           "parent": {
               "id": "444",
               "type": "parent type" 
               } 
        }
    }$$);
    

    The recursive query executes jsonb_each() for every json object found on any level. New key names contain full path from the root:

    with recursive flat (id, key, value) as (
        select id, key, value
        from my_table,
        jsonb_each(data)
    union
        select f.id, concat(f.key, '.', j.key), j.value
        from flat f,
        jsonb_each(f.value) j
        where jsonb_typeof(f.value) = 'object'
    )
    select id, jsonb_pretty(jsonb_object_agg(key, value)) as data
    from flat
    where jsonb_typeof(value) <> 'object'
    group by id;
    
     id |                   data                   
    ----+------------------------------------------
      1 | {                                       +
        |     "form": "a form",                   +
        |     "type": "a type",                   +
        |     "contact.name": "a name",           +
        |     "contact.type": "contact type",     +
        |     "contact.phone": "123-456-78",      +
        |     "contact.parent.id": "444",         +
        |     "contact.parent.type": "parent type"+
        | }
    (1 row)
    

    If you want to get a flat view of this data you can use the function create_jsonb_flat_view() described in this answer Flatten aggregated key/value pairs from a JSONB field?

    You need to create a table (or view) with flattened jsonb:

    create table my_table_flat as 
    -- create view my_table_flat as 
    with recursive flat (id, key, value) as (
    -- etc as above
    -- but without jsonb_pretty()
    

    Now you can use the function on the table:

    select create_jsonb_flat_view('my_table_flat', 'id', 'data');
    
    select * from my_table_flat_view;
    
    
     id | contact.name | contact.parent.id | contact.parent.type | contact.phone | contact.type |  form  |  type  
    ----+--------------+-------------------+---------------------+---------------+--------------+--------+--------
      1 | a name       | 444               | parent type         | 123-456-78    | contact type | a form | a type
    (1 row)
    

    The solution works in Postgres 9.5+, as it uses jsonb function introduced in this version. If your server version is older it is highly recommended to upgrade Postgres anyway to use jsonb efficiently.

    0 讨论(0)
提交回复
热议问题