Запрос для элементов массива внутри типа 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';