对平面 jsonb 数组元素的 LIKE 查询

mba*_*jur 3 arrays postgresql pattern-matching jsonb postgresql-9.6

我有一个posts带有类型列的Postgres 表jsonb基本上是一个扁平的标签数组。

我需要做的是以某种方式运行一个 LIKE 查询 tags列元素以便我可以找到具有以部分字符串开头的标签的帖子。

这样的事情在 Postgres 中可能吗?我一直在寻找超级复杂的例子,但没有人描述过这种基本和简单的场景。

我当前的代码可以很好地检查是否有具有特定标签的帖子:

select * from posts where tags @> '"TAG"'
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种在以下方面运行某些东西的方法

select * from posts where tags @> '"%TAG%"'
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 6

SELECT *
FROM   posts p
WHERE  EXISTS (
   SELECT FROM jsonb_array_elements_text(p.tags) tag
   WHERE  tag LIKE '%TAG%'
   );
Run Code Online (Sandbox Code Playgroud)

相关,有解释:

或者更简单的@?操作符,因为 Postgres 12 实现了 SQL/JSON:

SELECT *
--     optional to show the matching item:
--   , jsonb_path_query_first(tags, '$[*] ? (@ like_regex "^ tag" flag "i")')
FROM   posts
WHERE  tags @? '$[*] ? (@ like_regex "TAG")';
Run Code Online (Sandbox Code Playgroud)

运算符@?只是函数jsonb_path_exists()的包装器。所以这是等价的:

...
WHERE  jsonb_path_exists(tags, '$[*] ? (@ like_regex "TAG")');
Run Code Online (Sandbox Code Playgroud)

两者都没有索引支持。(@?稍后可能会为操作员添加,但在第 13 页中尚未添加)。所以这些查询对于大表来说很慢。像 Laurenz 已经建议的标准化设计会更好 - 具有三元组索引:

对于仅前缀匹配LIKE 'TAG%',没有前导通配符),您可以使其与全文索引一起使用

CREATE INDEX posts_tags_fts_gin_idx ON posts USING GIN (to_tsvector('simple', tags));
Run Code Online (Sandbox Code Playgroud)

和一个匹配的查询:

SELECT *
FROM   posts p
WHERE  to_tsvector('simple', tags)  @@ 'TAG:*'::tsquery
Run Code Online (Sandbox Code Playgroud)

或者englishsimple如果您想要词干自然英语,请使用字典而不是(或任何适合您的情况)。

to_tsvector(json(b))需要Postgres 10或更高版本。

有关的: