0

Suppose we have two columns: id, params. params is a jsonb column that contains arrays of objects like:

[
    {
        "prop": "a",
        "answer": "123"
    },
    {
        "prop": "b",
        "answer": "456"
    }
]

I need to create a query that returns id + answer where prop has some specific value (so at most one row per id).

For example, you can filter by prop=a, and in this case, you'll get 123 for that particular row. Other rows (with other ids) can have a different value or don't have it all (since there could be no prop=a in their jsons).

I tried some solutions with jsonb_array_elements(params) but I always ended up having all possible values from the json even if you have prop=a only in one of the elements (so id is duplicated in the result set with each answer). Also, I obviously cannot use solutions based on ordinality of the elements in the arrays.

Albina
  • 1,901
  • 3
  • 7
  • 19
amseager
  • 5,795
  • 4
  • 24
  • 47

2 Answers2

1

First flatten the table and then filter as suggested by Mike Organek. the_table CTE is a mimic of a real data table.

with the_table(id, params) as
(
 values
 (1, '[{"prop": "a", "answer": "123"},{"prop": "b", "answer": "456"}]'::jsonb),
 (2, '[{"prop": "a", "answer": "124"},{"prop": "b", "answer": "457"}]'),
 (3, '[{"prop": "a", "answer": "124"},{"prop": "c", "answer": "458"}]')
)
select id, j ->> 'answer' answer
from the_table cross join lateral jsonb_array_elements(params) j
where j ->> 'prop' = 'b';
id answer
1 456
2 457
Stefanov.sm
  • 11,215
  • 2
  • 21
  • 21
1

As it was suggested by Mike Organek, you can use jsonb_array_elements() function.
The final query can be as follows:

select id, 
       tmp.parameters->>'prop' AS property, 
       tmp.parameters->>'answer' AS answer
from data
left join LATERAL jsonb_array_elements(data.params) 
          WITH ORDINALITY AS tmp (parameters, row_number) ON true
where tmp.parameters->>'prop' = 'a';

Lateral join unwrappes jsonb object (top-level elements) and you get separate columns corresponding for 'prop' and 'answer' properties in a jsonb column.
Use where clause to filter the rows the way you need.

Here is a demo.

Also more can be found in this answer.

Albina
  • 1,901
  • 3
  • 7
  • 19