Запрос для элементов массива внутри типа JSON


Я пытаюсь проверить json введите PostgreSQL 9.3.
У меня есть под названием 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, поэтому я не знаю, что я делаю неправильно.

2 57

2 ответа:

json в Postgres 9.3+

Unnest массив JSON с функцией json_array_elements() в боковом соединении в 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';

The CTE (WITH запрос) просто заменяет таблицу 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().

лучше тем не менее, используйте новый оператор " содержит @> (лучше всего в сочетании с соответствующим индексом джина на выражение 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 массив, нам нужно сопоставить структуру в термине поиска и обернуть элемент массива в квадратные скобки. Удалите скобки массива при поиске простой записи.

подробное объяснение и другие варианты:

создать таблицу со столбцом типа 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';