2015-02-12 3 views
19

У меня есть таблица в базе данных postgresql 9.4 с полем jsonb, называемым приемниками. Некоторые примеры строки:Postgresql массив запросов объектов в поле JSONB

[{"id": "145119603", "name": "145119603", "type": 2}] 
[{"id": "1884595530", "name": "1884595530", "type": 1}] 
[{"id": "363058213", "name": "363058213", "type": 1}] 
[{"id": "1427965764", "name": "1427965764", "type": 1}] 
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}] 
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}] 
[{"id": "791712670", "name": "791712670", "type": 0}] 
[{"id": "895207852", "name": "895207852", "type": 0}] 
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}] 
[{"id": "1079725696", "name": "1079725696", "type": 0}] 

У меня есть список значений для идентификатора и хотят выбрать любую строку, содержащую объект с любым из значений этого списка, в пределах массива в jsonb поля.

Возможно ли это? Есть ли индекс GIN, который я могу сделать, это ускорит это?

ответ

31

Там не одна операция, которая может помочь вам, но у вас есть несколько вариантов:

1. Если у вас есть небольшой (и фиксированное) количество идентификаторов для запроса, вы можете использовать несколько сдерживания операторы @> в сочетании с or; f.ex .:

where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]' 

Простой gin индекс может помочь вам в вашей колонке данных здесь.

2. Если у вас есть переменное число идентификаторов (или у вас есть много из них), вы можете использовать json[b]_array_elements() для извлечения каждого элемента массива, создать список ID, а затем запросить его с any- сдерживание оператор ?|:

select * 
from jsonbtest 
where to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?| 
     array['1884595530', '791712670']; 

к сожалению, вы не можете индексировать выражение, которое имеет подзапрос в нем. Если вы хотите индексировать его, необходимо создать функцию для этого:

create function idlist_jsonb(jsonbtest) 
    returns jsonb 
    language sql 
    strict 
    immutable 
as $func$ 
    select to_json(array(select jsonb_array_elements($1.data) ->> 'id'))::jsonb 
$func$; 

create index on jsonbtest using gin (idlist_jsonb(jsonbtest)); 

После этого, вы можете запросить идентификаторы, как это:

select *, jsonbtest.idlist_jsonb 
from jsonbtest 
where jsonbtest.idlist_jsonb ?| array['193623800', '895207852']; 

Примечание: Я dot notation/computed field здесь, но вам не обязательно.

3. Но на данный момент вам не нужно придерживаться json [b]: у вас есть простой текстовый массив, который также поддерживается PostgreSQL.

create function idlist_array(jsonbtest) 
    returns text[] 
    language sql 
    strict 
    immutable 
as $func$ 
    select array(select jsonb_array_elements($1.data) ->> 'id') 
$func$; 

create index on jsonbtest using gin (idlist_array(jsonbtest)); 

И запросить это вычисленное поле с оператором массива перекрытия &&:

select *, jsonbtest.idlist_array 
from jsonbtest 
where jsonbtest.idlist_array && array['193623800', '895207852']; 

Примечания: Из моего внутреннего тестирования, это последнее решение рассчитываются с более высокой стоимостью, чем вариант jsonb, но на самом деле это быстрее, чем немного. Если производительность действительно важна для вас, вы должны проверить оба.

+1

Вот другой подход: http://dba.stackexchange.com/questions/130699/postgresql-json-query-array-against-multiple-values ​​ – Chrizt0f

+0

@ Chrizt0f это мой 1. подход ('ANY' может быть выражен выражениями' OR'ed '). Обычно в клиентских приложениях трудно привязать 'jsonb []', но если OP (или любой, кто заинтересован в этом) может это сделать, это также правильное решение, но обратите внимание, что он будет использовать индекс несколько раз, поэтому мой оригинальное примечание по-прежнему применяется (* Если у вас есть небольшой (и исправленный) (sic!) количество идентификаторов для запроса *) - но с 'ANY' удобнее поставлять нефиксированное количество идентификаторов OFC. – pozs

4

я найти обходной путь:
where data::text similar to '%("id": "145119603"|"id": "1884595530")%'

+0

, хотя он вызывает полный текстовый поиск за сканирование, это аккуратно – AnthonyJClink

Смежные вопросы