Запрос для элементов массива внутри типа 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'
? Я просмотрел эти источники, но до сих пор не могу получить его:
- http://www.postgresql.org/docs/9.3/static/functions-json.html
- как мне сделать запрос с использованием полей внутри новых возможностей PostgreSQL в формате JSON тип данных?
- http://michael.otacoo.com/postgresql-2/postgres-9-3-feature-highlight-json-operators/
Я тоже пробовал такие вещи, но безрезультатно:
SELECT json_array_elements(data->'objects') AS data from reports
WHERE data->>'src' = 'foo.png';
Я не эксперт по SQL, поэтому я не знаю, что я делаю неправильно.
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
.тесно связан ответ:
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';