I want to query a JSONB array using a regex filter. Following the docs, I should be able to do:
WHERE jsonb_path_exists(
data,
'$.value[*] ? (@ like_regex $foo flag "i")',
jsonb_build_object('foo', 'demo')
)
But I’m getting an error:
ERROR: syntax error at or near "$foo" of jsonpath input
I think it’s because $
is a valid regex character?
Here is some demo data:
INSERT INTO table_data (fields) VALUES
('[{"value": "Sales"}]'),
('[{"value": "CEO Staff"}]'),
('[{"value": "Procurement"'),
('[{"value": "CEO Staff"}]');
I wish to query all that have a value containing 'ceo'
.
2
Answers
I assume that the
fields
JSON array might contain more than one element and therefore I would first flatten using lateral join and then filter using the case-insensitive ‘regexp-match’ operator~*
.If
fields
JSON array always contains one element then simplyDB Fiddle demo
I can reproduce the problem. Parameter substitution works for other
jsonpath
operators like==
, but fails forlike_regex
. The manual does not seem to mention this restriction, though.I don’t think this it related to the special meaning of
$
in regexp expressions (which would be enclosed in double quotes). The error kicks in earlier. Looks like parameter substitution is just not supported there.There is a workaround: build a
jsonpath
expression dynamically:Using (optional)
format()
for convenient string concatenation. The string literal'"CEO"'
can be replaced by an expression – the target use case I presume?Then cast to
jsonpath
.The plot twist: this is superior anyway. It can use an index – as opposed to using the function
jsonb_path_exists()
! See:fiddle
Closely related (also look at the attached fiddle over there!):
Index usage is bound to operators internally, not functions. Some functions can be transformed by the query planner, but not in this case. Related: