postgresql 在JSON数组中搜索包含与模式匹配的值的对象

uemypmqf  于 2023-03-12  发布在  PostgreSQL
关注(0)|答案(2)|浏览(350)

我有一个带有jsonb列的数据库,其中每一行都包含一个名称值对数组。

[
    {"name":"foo", "value":"bar"},
    {"name":"biz", "value":"baz"},
    {"name":"beep", "value":"boop"}
]

如何查询包含部分值的行?例如,查找JSON对象键为value(如'%ba %')的行?
我知道可以使用SELECT * FROM tbl WHERE jsoncol @> '[{"value":"bar"}]'查找JSON为该特定值的行,但是如何查询包含模式的行呢?

o2gm4chl

o2gm4chl1#

Postgres 12或更高版本

使用SQL/JSON路径表达式,其中可以使用like_regex进行测试:

SELECT *
FROM   tbl t
WHERE  t.jsoncol @? '$[*].value ? (@ like_regex "ba" flag "i")';

仅添加flag "i"以进行不区分大小写的匹配。
可以创建索引。请参阅:

Postgres 11岁或以上

没有内置的jsonb操作符,也没有直接支持这种过滤器的索引。
我建议使用EXISTS半连接:

SELECT t.*
FROM   tbl t
WHERE  EXISTS (
   SELECT FROM jsonb_array_elements(t.jsoncol) elem
   WHERE  elem->>'value' LIKE '%ba%'
   );

它避免了冗余的计算,并且避免了最后的DISTINCT步骤,您将需要使用普通的CROSS JOIN来获得不同的行。
如果这仍然不够快,一种更复杂的特定查询类型的解决方案是在IMMUTABLE函数中提取每行唯一值的连接字符串(使用不会干扰搜索模式的分隔符),在函数表达式上构建三元组GIN索引,并在查询中使用相同的表达式。
相关:

另外,如果您的jsonb值确实与示例类似,则可以去除大量噪声并存储:

[
   {"foo":"bar"},
   {"biz":"baz"},
   {"beep":"boop"}
]
lc8prwob

lc8prwob2#

可以在横向连接中使用函数jsonb_array_elements(),并在WHERE子句中使用其结果value

select distinct t.* 
from my_table t
cross join jsonb_array_elements(jsoncol)
where value->>'value' like '%ba%'

有关distinct和性能的说明,请阅读How to query jsonb arrays with IN operator

相关问题