查询JSON类型内的数组元素


118

我正在尝试测试jsonPostgreSQL 9.3中的类型。
我在json名为data的表中有一个列reports。JSON看起来像这样:

{
  "objects": [
    {"src":"foo.png"},
    {"src":"bar.png"}
  ],
  "background":"background.png"
}

我想查询表中所有与“对象”数组中“ src”值匹配的报告。例如,是否可以在数据库中查询所有匹配的报告'src' = 'foo.png'?我成功地写了一个查询,可以匹配"background"

SELECT data AS data FROM reports where data->>'background' = 'background.png'

但是由于"objects"具有一组值,所以我似乎无法编写出有效的东西。是否可以在数据库中查询所有匹配的报告'src' = 'foo.png'?我已经查看了这些来源,但仍然无法了解:

我也尝试过类似的方法,但无济于事:

SELECT json_array_elements(data->'objects') AS data from reports
WHERE  data->>'src' = 'foo.png';

我不是SQL专家,所以我不知道我做错了什么。

Answers:


214

json 在Postgres 9.3+中

json_array_elements()通过FROM子句中的横向联接将函数与JSON数组嵌套在一起,并测试其元素:

WITH reports(data) AS (
   VALUES ('{"objects":[{"src":"foo.png"}, {"src":"bar.png"}]
           , "background":"background.png"}'::json)
   ) 
SELECT *
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

CTEWITH查询)只是替代了一张桌子reports
或者,等效于单层嵌套:

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>->以及#>操作符在手册中进行了说明。

这两个查询都使用隐式JOIN LATERAL

SQL提琴。

密切相关的答案:

jsonb 在Postgres 9.4+

使用等效项jsonb_array_elements()

更好的是,使用新的“ contains”运算符@>(最好与表达式上匹配的GIN索引结合使用data->'objects'):

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

由于键objects包含一个JSON 数组,因此我们需要匹配搜索项中的结构并将数组元素也包装在方括号中。搜索纯记录时,请放下数组括号。

详细说明和更多选项:


1
@pacothelovetaco:添加了针对jsonb/ pg 9.4 的更新。除了:对于简单的情况(1级嵌套),->操作员还可以json在9.3页中完成技巧。
Erwin Brandstetter 2015年

1
@pacothelovetaco,对于第9.3页,“#>”不是秘密调味品,“->”对于您的情况就很好了,因为它还会返回json objec。'#>'在嵌套json路径的情况下会更有用,因为它允许您轻松地在'{}'中指定路径
Gob00st 2015年

1
@>'[{“ src”:“ foo.png”}]''; 在什么条件下可以正常工作,但是如何删除这样的特定对象?我不知道这个物体的索引。我想按键值删除。
Pranay Soni

1
@PranaySoni:请问新问题。评论不是地方。您可以始终链接到此上下文。
Erwin Brandstetter,2016年

亲爱的@ErwinBrandstetter,是否可以通过部分匹配找到两个文档?例如,我想同时获得两条记录,例如'[{“ src”:“。png”}]'
Pyrejkee

8

创建一个列为json类型的表

CREATE TABLE friends ( id serial primary key, data jsonb);

现在让我们插入json数据

INSERT INTO friends(data) VALUES ('{"name": "Arya", "work": ["Improvements", "Office"], "available": true}');
INSERT INTO friends(data) VALUES ('{"name": "Tim Cook", "work": ["Cook", "ceo", "Play"], "uses": ["baseball", "laptop"], "available": false}');

现在让我们进行一些查询以获取数据

select data->'name' from friends;
select data->'name' as name, data->'work' as work from friends;

您可能已经注意到,结果附带了逗号(“)”和方括号([])

    name    |            work            
------------+----------------------------
 "Arya"     | ["Improvements", "Office"]
 "Tim Cook" | ["Cook", "ceo", "Play"]
(2 rows)

现在只检索值即可 ->>

select data->>'name' as name, data->'work'->>0 as work from friends;
select data->>'name' as name, data->'work'->>0 as work from friends where data->>'name'='Arya';

22
这是令人愉快的格式化噪音,与问题无关。
Erwin Brandstetter

4
我发现这很有用。显示了如何在jsonb中钻取数组
GavinBelson

0

从表中选择data->'objects'-> 0->'src'作为SRC,其中data->'objects'-> 0->'src'='foo.png'


2
只有当你知道的指数,该指数是0。这将是有益的
Buyut佐戈Rivai

是的,但是有一种方法可以爆炸数组对象,它将按行映射,我们可以使用它。如果我错了,请纠正我。
anand shukla

不是一个很好的解决方案,你也不能肯定,“SRC”是在0位置
simUser
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.