Merging JSONB values in PostgreSQL?

后端 未结 3 941
生来不讨喜
生来不讨喜 2020-12-02 01:51

Using the || operator yields the following result:

select \'{\"a\":{\"b\":2}}\'::jsonb || \'{\"a\":{\"c\":3}}\'::jsonb ;
    ?column?     
-----         


        
3条回答
  •  心在旅途
    2020-12-02 02:43

    This kind of "deep merge" can be interpreted quite differently, depending on your use case. For completeness, my intuition usually dictates the following rules:

    • object + object: Every property survives from each object, which is not in the other object (JSON's null value is considered to be in the object, if it's explicitly mentioned). When a property is in both objects, the merge continues recursively with the same rules (this point is usually agreed on).
    • array + array: The result is the concatenation of the two arrays.
    • array + primitive/object: the result is the first array, with the second JSON value appended to it.
    • any other cases: The result is the second JSON value (so f.ex. primitives or incompatible types override each other).

    create or replace function jsonb_merge_deep(jsonb, jsonb)
      returns jsonb
      language sql
      immutable
    as $func$
      select case jsonb_typeof($1)
        when 'object' then case jsonb_typeof($2)
          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
                        else jsonb_merge_deep(e1.v, e2.v)
                      end)
            from      jsonb_each($1) e1(k, v)
            full join jsonb_each($2) e2(k, v) using (k)
          )
          else $2
        end
        when 'array' then $1 || $2
        else $2
      end
    $func$;
    

    This function's added bonus is that it can be called with literally any type of JSON values: always produces a result & never complains about JSON value types.

    http://rextester.com/FAC95623

提交回复
热议问题