PostgreSQL-在json数组中查找属性的组合以及检查属性的存在

时间:2019-01-08 10:40:28

标签: postgresql jsonb postgresql-10

我按照Erwin Brandstetter在finding using attribute combinations上的回答。我也有类似的问题,但有所不同。

假设我的数据如下:

CREATE TABLE tracks (id serial, data jsonb);

INSERT INTO tracks (id, data)  VALUES
  (1, '[{"artist": "Simple Plan",    "title": "Welcome to My Life"}]')
, (2, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"}]')
, (3, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"},
        {"artist": "Simple Plan",    "title": "Perfect"} 
       ]')
, (4, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect",  "year": "2005"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"},
        {"artist": "Simple Plan",    "title": "Perfect"} 
       ]');

我也在使用相同的索引:gin (data jsonb_path_ops)

当我查询时:

SELECT * FROM tracks
WHERE  data @> '[{"artist": "Simple Plan", "title": "Welcome to My Life"}]';

它将返回1, '[{"artist": "Simple Plan", "title": "Welcome to My Life"}]'

当我查询时:

SELECT * FROM tracks
WHERE  data @> '[{"artist": "Simple Plan", "title": "Perfect"}]';

它将返回

(2, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"}]')
,(3, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"},
        {"artist": "Simple Plan",    "title": "Perfect"} 
       ]')
,(4, '[{"artist": "Another Artist", "title": "Welcome to My Life"},
        {"artist": "Simple Plan",    "title": "Perfect",  "year": "2005"},
        {"artist": "Simple Plan",    "title": "Perfect", "awarded": "True"},
        {"artist": "Simple Plan",    "title": "Perfect"} 
       ]')

现在我想做些与上述线程不同的事情

  1. 仅想获取与查询匹配的每个id的json部分,即仅元素{“ artist”:“ Simple Plan”,“ title”:“ Perfect”}}

    < / li>
  2. 要匹配仅未授予的标题条目。为了节省空间,如果授予标题,我只存储“已授予”:“正确”。否则,将不存在“已授予”字段,这表示标题尚未授予。

所以输出将类似于:

(3, '[ {"artist": "Simple Plan",    "title": "Perfect"} 
       ]')
,(4, '[{"artist": "Simple Plan",    "title": "Perfect",  "year": "2005"},
        {"artist": "Simple Plan",    "title": "Perfect"} 
       ]')

为此,我尝试遵循Erwin's another answer。 但问题是id = 4将在结果中包含两行,而我想为一个id的单行条目

这可以实现吗?

由于我拥有庞大的数据集,因此我将对结果数应用LIMIT。此信息可能与此问题无关。我之所以提到它,是因为目前我正在查询

SELECT * FROM tracks
WHERE  data @> '[{"artist": "Simple Plan", "title": "Perfect"}]
LIMIT 20;

,然后在返回的sql结果中,我正在检查是否提及“ awarded”字段。如果存在“已授予”字段,那么我将忽略该元素。我了解这不是进行查询的有效方法。另外,由于我忽略了元素作为后期处理的一部分,所以最终得到的元素数量也减少了。

环境:我正在使用postgreSQL 10。

我希望我的问题是可以理解的。

1 个答案:

答案 0 :(得分:0)

如果要获取整个json数组,只需使用单词not

select * 
from tracks
where not data @> '[{"awarded": "True"}]'

 id |                            data                            
----+------------------------------------------------------------
  1 | [{"title": "Welcome to My Life", "artist": "Simple Plan"}]
(1 row)

如果要获取数组元素,则应使用jsonb_array_elements()取消嵌套数组:

select id, jsonb_agg(element) as data
from tracks
cross join jsonb_array_elements(data) as element
where 
    element->>'artist' = 'Simple Plan'
    and element->>'title' = 'Perfect'
    and element->>'awarded' is distinct from 'True'
group by id
order by id 

 id |                                                      data                                                      
----+----------------------------------------------------------------------------------------------------------------
  3 | [{"title": "Perfect", "artist": "Simple Plan"}]
  4 | [{"year": "2005", "title": "Perfect", "artist": "Simple Plan"}, {"title": "Perfect", "artist": "Simple Plan"}]
(2 rows)

请注意,您应该使用is distinct from而不是<>,因为如果元素不包含键null,则表达式可能是awarded