查询JSON类型中的数组元素

pac*_*aco 96 sql postgresql json lateral jsonb

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

{
  "objects": [
    {"src":"foo.png"},
    {"src":"bar.png"}
  ],
  "background":"background.png"
}
Run Code Online (Sandbox Code Playgroud)

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

SELECT data AS data FROM reports where data->>'background' = 'background.png'
Run Code Online (Sandbox Code Playgroud)

但由于"objects"有一系列的价值观,我似乎无法写出有用的东西.是否可以在数据库中查询匹配的所有报告'src' = 'foo.png'?我查看了这些来源,但仍然无法得到它:

我也尝试过这样的事情,但无济于事:

SELECT json_array_elements(data->'objects') AS data from reports
WHERE  data->>'src' = 'foo.png';
Run Code Online (Sandbox Code Playgroud)

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

Erw*_*ter 177

json 在Postgres 9.3+

使用子句json_array_elements()中的横向连接中的函数来对JSON数组进行Unnest FROM并测试其元素:

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';
Run Code Online (Sandbox Code Playgroud)

CTE(WITH查询)只是替代了一张桌子reports.
或者,相当于只是一个单一的嵌套层次:

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

->>,->#>运营商的说明书中介绍.

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

SQL小提琴.

密切相关的答案:

jsonb 在Postgres 9.4+

使用等效的jsonb_array_elements().

更好的是,使用新的"包含"运算符@>(最好结合表达式上匹配的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"}]';
Run Code Online (Sandbox Code Playgroud)

由于密钥objects包含JSON 数组,因此我们需要匹配搜索项中的结构并将数组元素包装到方括号中.搜索普通记录时删除数组括号.

详细说明和更多选项:


小智 7

创建一个列为json类型的表

# CREATE TABLE friends ( id serial primary key, data jsonb);
Run Code Online (Sandbox Code Playgroud)

现在让我们插入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}');
Run Code Online (Sandbox Code Playgroud)

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

# select data->'name' from friends;

# select data->'name' as name, data->'work' as work from friends;
Run Code Online (Sandbox Code Playgroud)

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

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

现在只检索使用的值 ->>

# 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';
Run Code Online (Sandbox Code Playgroud)

  • 这是令人愉快的格式化噪音,与问题无关。 (13认同)
  • 我发现这很有用。显示如何在jsonb中钻取数组 (3认同)
  • 发现了很多复杂的方法,但这是如此简单易懂! (2认同)