Skip to content

Instantly share code, notes, and snippets.

@jarppe
Created April 6, 2021 11:18
Show Gist options
  • Save jarppe/f3cdd32ec58a4bdfb29daa67ef6c3b78 to your computer and use it in GitHub Desktop.
Save jarppe/f3cdd32ec58a4bdfb29daa67ef6c3b78 to your computer and use it in GitHub Desktop.
PostgreSQL function to produce diff of two jsonb objects. Does not support arrays.
--
-- Helper function to produce a diff of two jsonb values.
--
-- Accepts:
-- val1: original jsonb value
-- val2: updated jsonb value
--
-- Returns:
-- jsonb of changed values
--
-- Examples:
-- val1: {"a": {"b": 1}}
-- val2: {"a": {"b": 1, "c": 2}}
-- returns: {"a": {"c": 2}}
--
create or replace function jsonb_diff
(old jsonb, new jsonb)
returns jsonb
language 'plpgsql'
as
$$
declare
result jsonb;
object_result jsonb;
k text;
v record;
empty jsonb = '{}'::jsonb;
begin
if old is null or jsonb_typeof(old) = 'null'
then
return new;
end if;
if new is null or jsonb_typeof(new) = 'null'
then
return empty;
end if;
result = old;
for k in select * from jsonb_object_keys(old)
loop
result = result || jsonb_build_object(k, null);
end loop;
for v in select * from jsonb_each(new)
loop
if jsonb_typeof(old -> v.key) = 'object' and jsonb_typeof(new -> v.key) = 'object'
then
object_result = audit_public.jsonb_diff(old -> v.key, new -> v.key);
if object_result = empty
then
result = result - v.key;
else
result = result || jsonb_build_object(v.key, object_result);
end if;
elsif old -> v.key = new -> v.key
then
result = result - v.key;
else
result = result || jsonb_build_object(v.key, v.value);
end if;
end loop;
return result;
end;
$$;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment