我想使用正则表达式过滤器查询 JSONB 数组。按照docs,我应该能够做到:
WHERE jsonb_path_exists(
data,
'$.value[*] ? (@ like_regex $foo flag "i")',
jsonb_build_object('foo', 'demo')
)
但我收到错误:
ERROR: syntax error at or near "$foo" of jsonpath input
我认为这是因为
$
是一个有效的正则表达式字符?
这是一些演示数据:
INSERT INTO table_data (fields) VALUES
('[{"value": "Sales"}]'),
('[{"value": "CEO Staff"}]'),
('[{"value": "Procurement"'),
('[{"value": "CEO Staff"}]');
我想查询所有包含
'ceo'
的值。
jsonpath
运算符,例如 ==
,但对于 like_regex
则失败。不过手册似乎没有提到这个限制。
我认为这与正则表达式中
$
的特殊含义(用双引号括起来)无关。错误较早出现。看起来那里不支持参数替换。
有一个 解决方法:动态构建
jsonpath
表达式并使用关联的 Postgres 运算符 @?
:
SELECT *
FROM tbl
WHERE data @? format('$[*].value ? (@ like_regex %s flag "i")', '"CEO"')::jsonpath;
format()
方便字符串连接。字符串文字 '"CEO"'
可以用表达式替换 - 我推测的目标用例?jsonpath
。
情节转折:无论如何,这都是优越。它可以使用 index - 而不是使用函数
jsonb_path_exists()
! (并且运算符 @?
不允许从一开始就进行参数替换。)CREATE INDEX ON tbl USING gin (data jsonb_path_ops);
密切相关(另请参阅那边附加的小提琴!):
索引的使用在内部绑定到运算符,而不是函数。某些函数可以由查询规划器转换,但在本例中不行。相关:
我假设
fields
JSON 数组可能包含多个元素,因此我首先使用横向连接进行展平,然后使用不区分大小写的“regexp-match”运算符进行过滤~*
。
select fields, f -- or whatever else you might need
from table_data
cross join lateral jsonb_array_elements(fields) f
where f->>'value' ~* '\yCEO\y';
如果
fields
JSON 数组始终包含一个元素,那么只需
select fields from table_data
where fields->0->>'value' ~* '\yCEO\y';
DB Fiddle 演示