I have a table with an id and the json column prod
as the structure below
{
"1": {
"product": "chain",
"spare_part": [],
"sp_done": 0
},
"2": {
"product": "bike",
"spare_part": {
"1": {"part": "pedal", ...},
"2": {"part": "switch gear", ...},
...
},
"sp_done": 1
}
}
How can I get a table like
id | product | spare_part | sp_done |
---|---|---|---|
1 | chain | ||
2 | bike | pedal | 1 |
2 | bike | switch gear | 1 |
Thanks very much in advance.
2
Answers
You will have to write a function that loops over the nested JSON data and transforms it in a flat Array containing the data in the form that you need. If you want to write that function in JavaScript, you can use functions like
Object.fromEntries
,map
,flatMap
.Your data has spare_part once as an (empty) array, and once as an object. I assume you meant to use an array in both cases, and will present a solution for this. The basic idea is to pick elements from inner nodes of the JSON tree, expand children of these nodes and join them with these elements, then also pick elements of child elements.
How does it work? The first CTE (input) is just a single JSON. The top-level object is then split with
jsonb_each
into rows, which contain the key k and value v. The query takes the id from k and the product and sp_done fields from p as parts of theresult. It then splits the spare_parts field with
jsonb_array_elements
, and joinsthem. This joins each child row (array element) with its parent row. Then,
coalesce(spare_part->>'part', '')
takes the part field from each spare_part arrayelement, using an empty string instead of null.
The last join is a left join, to make sure that products get an entry even if their
spare_parts array is empty. The JSON fields are extracted with
->>
, whichdirectly converts the JSON to text.
The output is:
View on DB Fiddle.
This can be generalized to include spare_part fields which are objects, too, by
adding a second join, the first to process arrays, the second to process objects.
But it would be tedious, so a uniform structure (all arrays) is preferable.