我有一个表 users
,其中有一个名为 data
的 jsonb
字段。我必须检索所有在该 data
列中具有匹配给定字符串的 value 的用户。例如:
user1 = data: {"property_a": "a1", "property_b": "b1"}
user2 = data: {"property_a": "a2", "property_b": "b2"}
我想检索具有与 'b2'
匹配的值 data
的任何用户,在本例中为 'user2'
。
知道如何以优雅的方式做到这一点吗?我可以从所有用户的 data
中检索所有键并手动创建查询,但这既不快速也不优雅。
此外,我必须检索匹配的键和值,但首先要做的是。
最佳答案
没有简单的方法。 Per documentation:
GIN indexes can be used to efficiently search for keys or key/value pairs occurring within a large number of jsonb documents (datums)
大胆强调我的。没有所有值 的索引。 (它们可能具有不兼容的数据类型!)如果您不知道所有键的名称,则必须检查每一行中的所有 JSON 值。
如果像您演示的那样只有两个键(或者只有几个众所周知的键),它仍然很容易:
SELECT *
FROM users
WHERE data->>'property_a' = 'b2' OR
data->>'property_b' = 'b2';
可以用一个简单的 expression index 来支持:
CREATE INDEX foo_idx ON users ((data->>'property_a'), (data->>'property_b'))
或者使用 GIN 索引:
SELECT *
FROM users
WHERE data @> '{"property_a": "b2"}' OR
data @> '{"property_b": "b2"}'
CREATE INDEX bar_idx ON users USING gin (data jsonb_path_ops);
如果您不知道所有键名,事情就会变得更加复杂......
你可以使用 jsonb_each()
or jsonb_each_text()
将所有值取消嵌套到一个集合中,然后使用 ANY
构造进行检查:
SELECT *
FROM users
WHERE jsonb '"b2"' = ANY (SELECT (jsonb_each(data)).value);
或者
...
WHERE 'b2' = ANY (SELECT (jsonb_each_text(data)).value);
db<> fiddle here
但是最后一个没有索引支持。您可以改为将所有值提取到数组中并在其上创建表达式索引,然后在查询中使用数组运算符匹配该表达式...
相关:
关于sql - 如何在postgres中过滤json的任何键的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29609161/