get the value of nodeValue
of the rows where key = 'key3' AND key = 'key4'
.
Best use the jsonb
"contains" operator @>
:
SELECT customerid, customerOrders->'nodeValue'
FROM customer
WHERE customerOrders->'nodeValue' @> '[{"key": "key3"}]'
AND customerOrders->'nodeValue' @> '[{"key": "key4"}]';
To make it fast for big tables support it with an index. Ideally a jsonb_path_ops
index:
CREATE INDEX customer_nodeValue_idx ON customer
USING gin ((customerOrders->'nodeValue') jsonb_path_ops); -- parentheses required
See:
The later version of your question is a bit more tricky:
return the value of 'key3' and 'key4'
SELECT c.customerid, o.values
FROM customer c
CROSS JOIN LATERAL (
SELECT ARRAY(
SELECT o.ord->>'value'
FROM jsonb_array_elements(c.customerOrders->'nodeValue') o(ord)
WHERE (o.ord->>'key' = 'key3' OR
o.ord->>'key' = 'key4')
)
) o(values)
WHERE c.customerOrders->'nodeValue' @> '[{"key": "key3"}]'
AND c.customerOrders->'nodeValue' @> '[{"key": "key4"}]';
First filter qualifying rows like above (with a fast index lookup). Then unnest the JSON document and build your answer in a LATERAL
subquery. Should be simplest, cleanest and fastest. For the technique, see:
I added customerid
to the result of both queries to identify rows. That's optional.
db<>fiddle here (demonstrating both)
Design
You might simplify your bloated JSON layout to something like:
'{
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4",
"key5": "value5"
}'
Or at least:
'[
{
"key1": "value1"
},
{
"key2": "value2"
},
{
"key3": "value3"
},
{
"key4": "value4"
},
{
"key5": "value5"
}
]'
Would make everything considerably simpler, smaller and faster.