I’ve a JSONB inside a PostgreSQL table with this structure (more or less)
{
"obj1": {
"obj2": {
"obj3": [
{
"obj4": {
"obj": "A"
}
},
{
"obj4": {
"obj": "B"
}
}
]
}
}
}
Then my obj3 is an array of objects and I wanna the obj inside obj4 separated by comma.
Thus what I really need is something like:
1 | A,B
2 | C,D
3 | NULL
I’m using PostgreSql 14. Any help is going to be appreciate.
and I’ve got this
SELECT t.id,
jsonb_path_query(t.b,
'$."obj1"."obj2"."obj3"[*]."obj4"."obj"' ::jsonpath) AS obj5
FROM (VALUES(1,
'{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"A"}},{"obj4":{"obj":"B"}}]}}}'
::jsonb), (2,
'{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"C"}},{"obj4":{"obj":"D"}}]}}}'
::jsonb), (3, '{}' ::jsonb)) t(id, b);
But the json_path_query multiply the rows and remove not found results as well...
3
Answers
You need to group the resulting rows by
t.id
so that to group A & B, and C & D on the same row while using thestring_agg
function to group them in the same resulting column with ‘,’ as separator.But to do so, you need first to switch the
jsonb_path_query
function from theSELECT
clause to theFROM
clause while introducing aLEFT JOIN
so that to keep the rows with no output from thejsonb_path_query
function.The solution is :
see dbfiddle
Inside-out: climb the object tree, flatten the array and then select/aggregate. DB fiddle
For the sake of clarity/reuse, I’d create a function to convert the jsonb array to a Postgres array.
Then this query should return what you want.
If you really want a string returned instead of an array, change the function to return
text
instead oftext[]
and usestring_agg(t, ',')
instead ofarray_agg(t)
.