JSONB数组包含OR和AND运算符

时间:2018-09-19 07:21:15

标签: sql json postgresql jsonb

考虑表temp (jsondata jsonb)

Postgres提供了一种使用

查询jsonb数组对象以进行包含检查的方法
SELECT jsondata 
FROM temp 
WHERE (jsondata->'properties'->'home') ? 'football'

但是,我们不能对数组包含使用LIKE运算符。使数组中包含LIKE的一种方法是使用-

SELECT jsondata 
FROM temp,jsonb_array_elements_text(temp.jsondata->'properties'->'home') 
WHERE value like '%foot%'

与LIKE的OR操作可以通过使用-

SELECT DISTINCT jsondata 
FROM temp,jsonb_array_elements_text(temp.jsondata->'properties'->'home') 
WHERE value like '%foot%' OR value like 'stad%'

但是,我无法使用JSONB数组包含中的LIKE运算符执行AND操作。

3 个答案:

答案 0 :(得分:1)

After unnesting the array with jsonb_array_elements() you can check values meeting one of the conditions and sum them in groups by original rows, example:

drop table if exists temp;
create table temp(id serial primary key, jsondata jsonb);
insert into temp (jsondata) values
    ('{"properties":{"home":["football","stadium","16"]}}'),
    ('{"properties":{"home":["football","player","16"]}}'),
    ('{"properties":{"home":["soccer","stadium","16"]}}');

select jsondata
from temp 
cross join jsonb_array_elements_text(temp.jsondata->'properties'->'home') 
group by jsondata 
-- or better:
-- group by id
having sum((value like '%foot%' or value like 'stad%')::int) = 2

                        jsondata                         
---------------------------------------------------------
 {"properties": {"home": ["football", "stadium", "16"]}}
(1 row)

Update. The above query may be expensive with a large dataset. There is a simplified but faster solution. You can cast the array to text and apply like to it, e.g.:

select jsondata
from temp 
where jsondata->'properties'->>'home' like all('{%foot%, %stad%}');

                        jsondata                         
---------------------------------------------------------
 {"properties": {"home": ["football", "stadium", "16"]}}
(1 row) 

答案 1 :(得分:0)

I have the following, but it was a bit fiddly. There's probably a better way but this is working I think.

The idea is to find the matching JSON array entries, then collect the results. In the join condition we check the "matches" array has the expected number of entries.

CREATE TABLE temp (jsondata jsonb);

INSERT INTO temp VALUES ('{"properties":{"home":["football","stadium",16]}}');

SELECT jsondata FROM temp t
INNER JOIN LATERAL (
    SELECT array_agg(value) AS matches
    FROM jsonb_array_elements_text(t.jsondata->'properties'->'home')
    WHERE value LIKE '%foo%' OR value LIKE '%sta%'
    LIMIT 1        
) l ON array_length(matches, 1) = 2;

                           jsondata                        
-------------------------------------------------------
 {"properties": {"home": ["football", "stadium", 16]}}
(1 row)

答案 2 :(得分:0)

demo: db<>fiddle

我将数组转换为文本。然后,您可以使用每个字符串运算符搜索关键字。

缺点:因为它是一个数组,所以文本包含大括号和逗号之类的字符。因此,搜索以某个开头(ABC%)为开头的关键字并不是那么简单:您总是必须像%ABC%

一样进行搜索
SELECT jsondata
FROM (
    SELECT 
        jsondata, 
        jsondata->'properties'->>'home' as a
    FROM 
        temp
)s
WHERE 
    a LIKE '%stad%' AND a LIKE '%foot%'