, . " " , jsonb- "" - , . , jsonb, , .
:
CREATE OR REPLACE FUNCTION jsonb_diff_val(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
result JSONB;
object_result JSONB;
i int;
v RECORD;
BEGIN
IF jsonb_typeof(val1) = 'null'
THEN
RETURN val2;
END IF;
result = val1;
FOR v IN SELECT * FROM jsonb_each(val1) LOOP
result = result || jsonb_build_object(v.key, null);
END LOOP;
FOR v IN SELECT * FROM jsonb_each(val2) LOOP
IF jsonb_typeof(val1->v.key) = 'object' AND jsonb_typeof(val2->v.key) = 'object'
THEN
object_result = jsonb_diff_val(val1->v.key, val2->v.key);
-- check if result is not empty
i := (SELECT count(*) FROM jsonb_each(object_result));
IF i = 0
THEN
result = result - v.key; --if empty remove
ELSE
result = result || jsonb_build_object(v.key,object_result);
END IF;
ELSIF val1->v.key = val2->v.key THEN
result = result - v.key;
ELSE
result = result || jsonb_build_object(v.key,v.value);
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql;
:
SELECT jsonb_diff_val(
'{"a":"aaa", "b":{"b1":"b","b2":"bb","b3":{"b3a":"aaa","b3c":"ccc"}}, "c":"ccc"}'::jsonb,
'{"a":"aaa", "b":{"b1":"b1","b3":{"b3a":"aaa","b3c":"cccc"}}, "d":"ddd"}'::jsonb
);
jsonb_diff_val
-------------------------------------------------------------------------------
{"b": {"b1": "b1", "b2": null, "b3": {"b3c": "cccc"}}, "c": null, "d": "ddd"}
(1 row)