简体   繁体   English

如何过滤postgres中json任意键的值

[英]How to filter a value of any key of json in postgres

I have a table users with a jsonb field called data .我有一个表users有一个名为datajsonb字段。 I have to retrieve all the users that have a value in that data column matching a given string.我必须检索在该data列中具有与给定字符串匹配的值的所有用户。 For example:例如:

user1 = data: {"property_a": "a1", "property_b": "b1"}
user2 = data: {"property_a": "a2", "property_b": "b2"}

I want to retrieve any user that has a value data matching 'b2' , in this case that will be 'user2' .我想检索具有匹配'b2'data任何用户,在本例中为'user2'

Any idea how to do this in an elegant way?知道如何以优雅的方式做到这一点吗? I can retrieve all keys from data of all users and create a query manually but that will be neither fast nor elegant.我可以从所有用户的data中检索所有键并手动创建查询,但这既不快速也不优雅。

In addition, I have to retrieve the key and value matched, but first things first.此外,我必须检索匹配的键和值,但首先要做的是。

There is no easy way.没有简单的方法。 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) GIN 索引可用于有效搜索大量 jsonb 文档(数据)中出现的键或键/值对

Bold emphasis mine.大胆强调我的。 There is no index over all values .所有都没有索引。 (Those can have non-compatible data types!) If you do not know the name(s) of all key(s) you have to inspect all JSON values in every row. (那些可能具有不兼容的数据类型!)如果您不知道所有键的名称,则必须检查每一行中的所有 JSON 值。

If there are just two keys like you demonstrate (or just a few well-kown keys), it's still easy enough:如果像您演示的那样只有两个键(或只有几个众所周知的键),它仍然很容易:

SELECT *
FROM   users
WHERE  data->>'property_a' = 'b2' OR
       data->>'property_b' = 'b2';

Can be supported with a simpleexpression index :可以通过简单的表达式索引来支持:

CREATE INDEX foo_idx ON users ((data->>'property_a'), (data->>'property_b'))

Or with a GIN index:或者使用 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);

If you don't know all key names, things get more complicated ...如果你不知道所有的键名,事情会变得更复杂......

You could use jsonb_each() or jsonb_each_text() to unnest all values into a set and then check with an ANY construct:您可以使用jsonb_each()jsonb_each_text()将所有值jsonb_each_text()到一个集合中,然后使用ANY构造进行检查:

SELECT *
FROM   users
WHERE  jsonb '"b2"' = ANY (SELECT (jsonb_each(data)).value);

Or或者

...
WHERE  'b2' = ANY (SELECT (jsonb_each_text(data)).value);

db<>fiddle here db<> 在这里摆弄

But there is no index support for the last one.但是最后一个没有索引支持。 You could instead extract all values into and array and create an expression index on that, and match that expression in queries with array operators ...您可以改为将所有值提取到数组中并在其上创建一个表达式索引,并将查询中的该表达式与数组运算符进行匹配...

Related:有关的:

Try this query.试试这个查询。

SELECT * FROM users
WHERE data::text LIKE '%b2%'

Of course it won't work if your key will contain such string too.当然,如果您的密钥也包含这样的字符串,它将不起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM