Postgres 12 or newer
Use an SQL/JSON path expression, where you can test with like_regex
:
SELECT *
FROM tbl t
WHERE t.jsoncol @? '$[*].value ? (@ like_regex "ba" flag "i")';
Only add flag "i"
for case insensitive matching.
Can an index. See:
Postgres 11 or older
There are no built in jsonb
operators nor any indexes supporting this kind of filter directly (yet).
I suggest an EXISTS
semi-join:
SELECT t.*
FROM tbl t
WHERE EXISTS (
SELECT FROM jsonb_array_elements(t.jsoncol) elem
WHERE elem->>'value' LIKE '%ba%'
);
It avoids redundant evaluations and the final DISTINCT
step you would need to get distinct rows with a plain CROSS JOIN
.
If this still isn't fast enough, a way more sophisticated specialized solution for the given type of query would be to extract a concatenated string of unique values (with a delimiter that won't interfere with your search patterns) per row in an IMMUTABLE
function, build a trigram GIN index on the functional expression and use the same expression in your queries.
Related:
Aside, if your jsonb
values really look like the example, you could trim a lot of noise and just store:
[
{"foo":"bar"},
{"biz":"baz"},
{"beep":"boop"}
]