Reputation: 2734
I want to get array of chd_id's for each prod_id,
query below works but only with limit 1
i want exact result but with multiple rows
select
prod_id,
array_agg((select * from jsonb_array_elements(products.prod_prop) limit 1)->>'chd_id')
from products
group by prod_id
limit 10
current result:
Raw value of products.prod_prop
is
[{"val": ["xxx"], "chd_id": 25812}, {"val": ["yyy"], "chd_id": 2342}]
Without limit 1
i get ERROR: more than one row returned by a subquery used as an expression
Upvotes: 0
Views: 2037
Reputation:
I think you need to do this with a lateral join:
select prod_id,
array_agg(t.chd_id)
from products p
left join lateral (
select e ->> 'chd_id' as chd_id
from jsonb_array_elements(p.prod_prop) as t(e)
) t on true
group by prod_id
limit 10;
The outer join is needed in case there are empty prod_prop values
Apparently the data in the JSONB is sometimes an array and sometimes a plain object. If all "plain objects" are indeed empty values, you can work around that using:
select prod_id,
array_agg(t.chd_id) filter (where t.chd_id is not null)
from products p
left join lateral (
select e ->> 'chd_id' as chd_id
from jsonb_array_elements(nullif(p.prod_prop,'{}')) as t(e)
) t on true
group by prod_id
limit 10;
If you do indeed mix plain objects and arrays in that column, you need a different approach:
select prod_id,
array_agg(t.chd_id) filter (where t.chd_id is not null)
from products p
left join lateral (
select e ->> 'chd_id' as chd_id
from jsonb_array_elements(case jsonb_typeof(p.prod_prop)
when 'array' then p.prod_prop
else '[]'
end) as t(e)
) t on true
group by prod_id
limit 10;
Upvotes: 3
Reputation: 65278
You can use a CROSS JOIN
among the table and the subquery generated through use of jsonb_array_elements()
function :
SELECT p.prod_id, array_agg(j.e->>'chd_id') AS chd_id
FROM products p
CROSS JOIN jsonb_array_elements(prod_prop) j(e)
GROUP BY prod_id
Upvotes: 2