Запрос элементов массива внутри типа JSON
Я пытаюсь проверить тип json
в PostgreSQL 9.3.
У меня есть столбец json
с именем data
в таблице с именем reports
. JSON выглядит примерно так:
{
"objects": [
{"src":"foo.png"},
{"src":"bar.png"}
],
"background":"background.png"
}
Я хотел бы запросить таблицу для всех отчетов, которые соответствуют значению 'src' в массиве 'objects'. Например, можно ли запросить в БД все отчеты, соответствующие '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, поэтому я не знаю, что я делаю неправильно.
Ответы
Ответ 1
json
в Postgres 9.3 +
Уничтожьте массив 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';
CTE (WITH
query) просто заменяет таблицу reports
.
Или, эквивалентно только для одного уровня вложенности:
SELECT *
FROM reports r, json_array_elements(r.data->'objects') obj
WHERE obj->>'src' = 'foo.png';
->>
, ->
и #>
описаны в руководстве.
Оба запроса используют неявный JOIN LATERAL
.
SQL Fiddle.
Близкий ответ:
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"}]';
Так как ключ objects
содержит массив JSON, нам нужно сопоставить структуру в терминах поиска и обернуть элемент массива в квадратные скобки. Оставьте скобки массива при поиске простой записи.
Подробное объяснение и дополнительные параметры:
Ответ 2
Создайте таблицу со столбцом типа 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';
Ответ 3
выберите data-> 'objects' → 0-> 'src' как SRC из таблицы, где data-> 'objects' → 0-> 'src' = 'foo.png'