我按照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"}
]')
现在我想做些与上述线程不同的事情:
仅想获取与查询匹配的每个id的json部分,即仅元素{“ artist”:“ Simple Plan”,“ title”:“ Perfect”}}
< / li>要匹配仅未授予的标题条目。为了节省空间,如果授予标题,我只存储“已授予”:“正确”。否则,将不存在“已授予”字段,这表示标题尚未授予。
所以输出将类似于:
(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。
我希望我的问题是可以理解的。
答案 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
。