Проверьте, содержит ли массив Postgres JSON строку
у меня есть таблица для хранения информации о моих кроликов. Выглядит это так:
create table rabbits (rabbit_id bigserial primary key, info json not null);
insert into rabbits (info) values
('{"name":"Henry", "food":["lettuce","carrots"]}'),
('{"name":"Herald","food":["carrots","zucchini"]}'),
('{"name":"Helen", "food":["lettuce","cheese"]}');
Как найти кроликов, которые любят морковь? Я придумал вот что:
select info->>'name' from rabbits where exists (
select 1 from json_array_elements(info->'food') as food
where food::text = '"carrots"'
);
мне не нравится этот запрос. Это полный бардак.
Как кролик-хранитель, у меня нет времени, чтобы изменить мою схему базы данных. Я просто хочу как следует покормить своих кроликов. Есть ли более читаемый способ сделать этот запрос?
4 ответа:
начиная с PostgreSQL 9.4, вы можете использовать
?
оператор:select info->>'name' from rabbits where (info->'food')::jsonb ? 'carrots';
вы даже можете индексировать
?
запрос"food"
клавиша при переключении на jsonb тип:alter table rabbits alter info type jsonb using info::jsonb; create index on rabbits using gin ((info->'food')); select info->>'name' from rabbits where info->'food' ? 'carrots';
конечно, у вас, вероятно, нет времени для этого, как полный рабочий день кролика хранителя.
обновление: вот демонстрация улучшения производительности на столе 1,000,000 кроликов, где каждый кролик любит две пищи и 10% из них любят морковь:
d=# -- Postgres 9.3 solution d=# explain analyze select info->>'name' from rabbits where exists ( d(# select 1 from json_array_elements(info->'food') as food d(# where food::text = '"carrots"' d(# ); Execution time: 3084.927 ms d=# -- Postgres 9.4+ solution d=# explain analyze select info->'name' from rabbits where (info->'food')::jsonb ? 'carrots'; Execution time: 1255.501 ms d=# alter table rabbits alter info type jsonb using info::jsonb; d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots'; Execution time: 465.919 ms d=# create index on rabbits using gin ((info->'food')); d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots'; Execution time: 256.478 ms