How can I recursively flatten a nested jsonb in postgres which I don't know the depth and the field at each depth? (see example below)
A postgressql query to do the flattening would be much apreciated
{
"xx": "",
"xx": "",
"form": "xxx",
"type": "",
"content_type": "xxx",
"reported_date": ,
"contact": {
"imported_date": "",
"name": "",
"phone": "",
"alternate_phone": "",
"specialization": "",
"type": "",
"reported_date": ,
"parent": {
"_id": "xxx",
"_rev": "xxx",
"parent": "",
"type": "xxx"
}
}
}
I have searched in stack overflow but they only consider jsonb's which have a single depth and the keys are already known before
Example setup:
create table my_table(id int, data jsonb);
insert into my_table values
(1,
$${
"type": "a type",
"form": "a form",
"contact": {
"name": "a name",
"phone": "123-456-78",
"type": "contact type",
"parent": {
"id": "444",
"type": "parent type"
}
}
}$$);
The recursive query executes jsonb_each()
for every json object found on any level. New key names contain full path from the root:
with recursive flat (id, key, value) as (
select id, key, value
from my_table,
jsonb_each(data)
union
select f.id, concat(f.key, '.', j.key), j.value
from flat f,
jsonb_each(f.value) j
where jsonb_typeof(f.value) = 'object'
)
select id, jsonb_pretty(jsonb_object_agg(key, value)) as data
from flat
where jsonb_typeof(value) <> 'object'
group by id;
id | data
----+------------------------------------------
1 | { +
| "form": "a form", +
| "type": "a type", +
| "contact.name": "a name", +
| "contact.type": "contact type", +
| "contact.phone": "123-456-78", +
| "contact.parent.id": "444", +
| "contact.parent.type": "parent type"+
| }
(1 row)
If you want to get a flat view of this data you can use the function create_jsonb_flat_view()
described in this answer Flatten aggregated key/value pairs from a JSONB field?
You need to create a table (or view) with flattened jsonb:
create table my_table_flat as
-- create view my_table_flat as
with recursive flat (id, key, value) as (
-- etc as above
-- but without jsonb_pretty()
Now you can use the function on the table:
select create_jsonb_flat_view('my_table_flat', 'id', 'data');
select * from my_table_flat_view;
id | contact.name | contact.parent.id | contact.parent.type | contact.phone | contact.type | form | type
----+--------------+-------------------+---------------------+---------------+--------------+--------+--------
1 | a name | 444 | parent type | 123-456-78 | contact type | a form | a type
(1 row)
The solution works in Postgres 9.5+, as it uses jsonb function introduced in this version. If your server version is older it is highly recommended to upgrade Postgres anyway to use jsonb efficiently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With