Merging Concatenating JSON(B) columns in query

后端 未结 10 1530
不思量自难忘°
不思量自难忘° 2020-12-08 09:40

Using Postgres 9.4, I am looking for a way to merge two (or more) json or jsonb columns in a query. Consider the following table as an example:

相关标签:
10条回答
  • 2020-12-08 10:15

    This function would merge nested json objects

    create or replace function jsonb_merge(CurrentData jsonb,newData jsonb)
     returns jsonb
     language sql
     immutable
    as $jsonb_merge_func$
     select case jsonb_typeof(CurrentData)
       when 'object' then case jsonb_typeof(newData)
         when 'object' then (
           select    jsonb_object_agg(k, case
                       when e2.v is null then e1.v
                       when e1.v is null then e2.v
                       when e1.v = e2.v then e1.v 
                       else jsonb_merge(e1.v, e2.v)
                     end)
           from      jsonb_each(CurrentData) e1(k, v)
           full join jsonb_each(newData) e2(k, v) using (k)
         )
         else newData
       end
       when 'array' then CurrentData || newData
       else newData
     end
    $jsonb_merge_func$;
    
    0 讨论(0)
  • 2020-12-08 10:15

    Try this, if anyone having an issue for merging two JSON object

    select table.attributes::jsonb || json_build_object('foo',1,'bar',2)::jsonb FROM table where table.x='y';
    
    0 讨论(0)
  • 2020-12-08 10:15

    works well as an alternative to || when recursive deep merge is required (found here) :

    create or replace function jsonb_merge_recurse(orig jsonb, delta jsonb)
    returns jsonb language sql as $$
        select
            jsonb_object_agg(
                coalesce(keyOrig, keyDelta),
                case
                    when valOrig isnull then valDelta
                    when valDelta isnull then valOrig
                    when (jsonb_typeof(valOrig) <> 'object' or jsonb_typeof(valDelta) <> 'object') then valDelta
                    else jsonb_merge_recurse(valOrig, valDelta)
                end
            )
        from jsonb_each(orig) e1(keyOrig, valOrig)
        full join jsonb_each(delta) e2(keyDelta, valDelta) on keyOrig = keyDelta
    $$;
    
    0 讨论(0)
  • 2020-12-08 10:19

    Looks like nobody proposed this kind of solution yet, so here's my take, usng custom aggregate functions:

    create or replace aggregate jsonb_merge_agg(jsonb)
    (
        sfunc = jsonb_concat,
        stype = jsonb,
        initcond = '{}'
    );
    
    create or replace function jsonb_concat(a jsonb, b jsonb) returns jsonb
        as 'select $1 || $2'
        language sql
        immutable
        parallel safe
    ;
    

    Note: this is using || which replaces existing values at same path instead of deeply merging them.

    Now jsonb_merge_agg is accessible like so:

    select jsonb_merge_agg(some_col) from some_table group by something;
    
    0 讨论(0)
提交回复
热议问题