LIKE 查询平面 jsonb 数组的元素

LIKE query on elements of flat jsonb array

我有一个 Postgres table posts 有一个类型为 jsonb 的列,它基本上是一个平面标签数组。

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

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

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

select * from posts where tags @> '"TAG"'

我正在寻找一种方法来 运行在

的行中找到一些东西
select * from posts where tags @> '"%TAG%"'
SELECT *
FROM   posts p
WHERE  EXISTS (
   SELECT FROM jsonb_array_elements_text(p.tags) tag
   WHERE  tag LIKE '%TAG%'
   );

相关,有解释:

  • Search a JSON array for an object containing a value matching a pattern

或使用 @? operator 更简单,因为 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")';

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

...
WHERE  jsonb_path_exists(tags, '$[*] ? (@ like_regex "TAG")');

两者都没有索引支持。 (稍后可能会为 @? 运算符添加,但在第 13 页中还没有)。所以这些查询对于大表来说很慢。规范化设计 会更好 - 具有三元组索引:

  • PostgreSQL LIKE query performance variations

前缀匹配LIKE 'TAG%',无前导通配符),您可以使用全文索引:

CREATE INDEX posts_tags_fts_gin_idx ON posts USING GIN (to_tsvector('simple', tags));

以及匹配的查询:

SELECT *
FROM   posts p
WHERE  to_tsvector('simple', tags)  @@ 'TAG:*'::tsquery

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

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

相关: