Skip to content

Commit 87e8826

Browse files
authored
Create jsonb_unnest_recursive_distinct.sql
1 parent 0112591 commit 87e8826

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
create or replace function public.jsonb_unnest_recursive_distinct(data jsonb[])
2+
returns table(
3+
path text[],
4+
value jsonb,
5+
member_of text
6+
)
7+
immutable
8+
returns null on null input -- = strict
9+
parallel safe -- Postgres 10 or later
10+
security invoker
11+
language sql
12+
set search_path = ''
13+
as $func$
14+
--explain (analyse)
15+
with recursive r (path, value, member_of) as
16+
(
17+
select
18+
distinct --!!! also fix performance problem
19+
array[k.key],
20+
v.value,
21+
t.type
22+
from unnest(jsonb_unnest_recursive_distinct.data) as u(data)
23+
cross join jsonb_typeof(u.data) as t(type)
24+
left join jsonb_each(case t.type when 'object' then u.data end) as o(obj_key, obj_value) on true
25+
left join jsonb_array_elements(case t.type when 'array' then u.data end) with ordinality as a(arr_value, arr_key) on true
26+
cross join coalesce(o.obj_key, (a.arr_key - 1)::text) as k(key)
27+
cross join coalesce(o.obj_value, a.arr_value) as v(value)
28+
where t.type in ('object', 'array')
29+
and k.key is not null
30+
union --all
31+
select
32+
array_append(r.path, k.key),
33+
v.value,
34+
t.type
35+
from r
36+
cross join jsonb_typeof(r.value) as t(type)
37+
left join jsonb_each(case t.type when 'object' then r.value end) as o(obj_key, obj_value) on true
38+
left join jsonb_array_elements(case t.type when 'array' then r.value end) with ordinality as a(arr_value, arr_key) on true
39+
cross join coalesce(o.obj_key, (a.arr_key - 1)::text) as k(key)
40+
cross join coalesce(o.obj_value, a.arr_value) as v(value)
41+
where t.type in ('object', 'array')
42+
and k.key is not null
43+
)
44+
select r.*
45+
from r
46+
where jsonb_typeof(r.value) not in ('object', 'array');
47+
$func$;
48+
49+
comment on function public.jsonb_unnest_recursive_distinct(arr_data jsonb[])
50+
is 'Recursive parse nested JSONs (arrays and objects), returns distinct keys and its values';
51+
52+
------------------------------------------------------------------------------------------------------------------------
53+
--TEST
54+
55+
do $$
56+
begin
57+
assert (select count(*) = 9
58+
from public.jsonb_unnest_recursive_distinct(array[
59+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb,
60+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb,
61+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 2}'::jsonb
62+
])
63+
);
64+
end;
65+
$$;

0 commit comments

Comments
 (0)