Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3e76932

Browse files
authored
jsonb_unnest_recursive(jsonb[]) added
1 parent e8b8d5a commit 3e76932

File tree

1 file changed

+77
-4
lines changed

1 file changed

+77
-4
lines changed

‎functions/jsonb_unnest_recursive.sql‎

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,88 @@ $func$;
4747
comment on function public.jsonb_unnest_recursive(data jsonb) is 'Recursive parse nested JSON (arrays and objects), returns keys and its values';
4848

4949

50+
------------------------------------------------------------------------------------------------------------------------
51+
52+
create or replace function public.jsonb_unnest_recursive(arr_data jsonb[])
53+
returns table(
54+
path text[],
55+
value jsonb,
56+
member_of text
57+
)
58+
immutable
59+
returns null on null input -- = strict
60+
parallel safe -- Postgres 10 or later
61+
security invoker
62+
language sql
63+
set search_path = ''
64+
as $func$
65+
--explain (analyse)
66+
with recursive r (path, value, member_of) as
67+
(
68+
select
69+
array[k.key],
70+
v.value,
71+
t.type
72+
from unnest(arr_data) as u(data)
73+
cross join jsonb_typeof(u.data) as t(type)
74+
left join jsonb_each(case t.type when 'object' then u.data end) as o(obj_key, obj_value) on true
75+
left join jsonb_array_elements(case t.type when 'array' then u.data end) with ordinality as a(arr_value, arr_key) on true
76+
cross join coalesce(o.obj_key, (a.arr_key - 1)::text) as k(key)
77+
cross join coalesce(o.obj_value, a.arr_value) as v(value)
78+
where t.type in ('object', 'array')
79+
and k.key is not null
80+
union all
81+
select
82+
array_append(r.path, k.key),
83+
v.value,
84+
t.type
85+
from r
86+
cross join jsonb_typeof(r.value) as t(type)
87+
left join jsonb_each(case t.type when 'object' then r.value end) as o(obj_key, obj_value) on true
88+
left join jsonb_array_elements(case t.type when 'array' then r.value end) with ordinality as a(arr_value, arr_key) on true
89+
cross join coalesce(o.obj_key, (a.arr_key - 1)::text) as k(key)
90+
cross join coalesce(o.obj_value, a.arr_value) as v(value)
91+
where t.type in ('object', 'array')
92+
and k.key is not null
93+
)
94+
select r.*
95+
from r
96+
where jsonb_typeof(r.value) not in ('object', 'array');
97+
$func$;
98+
99+
comment on function public.jsonb_unnest_recursive(arr_data jsonb[]) is 'Recursive parse nested JSONs (arrays and objects), returns keys and its values';
100+
101+
------------------------------------------------------------------------------------------------------------------------
102+
--TEST
103+
50104
--TEST AND USING EXAMPLE
51105
select cardinality(path) as level, *
52106
from public.jsonb_unnest_recursive('{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb)
53107
order by level, member_of, path;
54108

55109
/*
56110
-- Example: find all emails in JSON data
57-
select path, value #>> '{}' as email
58-
from public.jsonb_unnest_recursive('[{"name":"Mike", "age": 45, "emails":[null, "mike.1977@gmail.com"]}]'::jsonb)
59-
where jsonb_typeof(value) = 'string'
60-
and public.is_email(value #>> '{}');
111+
select j.path, v.value as email
112+
from public.jsonb_unnest_recursive('[{"name":"Mike", "age": 45, "emails":[null, "mike.1977@gmail.com", ""]}]'::jsonb) as j
113+
cross join nullif(j.value #>> '{}', '') as v(value) --cast jsonb scalar to text (can be null)
114+
where jsonb_typeof(j.value) = 'string'
115+
and v.value is not null
116+
and public.is_email(v.value);
61117
*/
118+
119+
do $$
120+
begin
121+
assert (select COUNT(*) = 8
122+
from public.jsonb_unnest_recursive(
123+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb
124+
)
125+
);
126+
127+
assert (select COUNT(*) = 16
128+
from public.jsonb_unnest_recursive(array[
129+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb,
130+
'{"id":123,"g":null,"a":[9,8,4,5],"name":"unknown", "7": 3}'::jsonb
131+
])
132+
);
133+
end;
134+
$$;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /