2015-02-12 19 views
19

Mam tabelę w bazie danych PostgreSQL 9.4 z polem jsonb zwanym odbiornikami. Niektóre przykłady rzędy:Tablica zapytań PostgreSQL w obiektach 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}] 

że posiada listę wartości dla identyfikatora, a chce wybrać dowolny wiersz zawierający obiekt z jedną z wartości z tej listy, w tablicy w polu jsonb.

Czy to możliwe? Czy istnieje indeks GIN, który mogę zrobić, że to przyspieszy?

Odpowiedz

31

Nie ma jednej operacji, które mogą pomóc, ale masz kilka opcji:

1. Jeśli masz małe (i stałej) liczbę identyfikatorów do kwerendy, można użyć wielu pojemników operatorzy @> w połączeniu z or; f.ex .:

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

Prosty gin indeks może pomóc Ci w kolumnie danych tutaj.

2. Jeśli masz zmienną liczbę identyfikatorów (lub masz wiele z nich), można użyć json[b]_array_elements() wyodrębnić każdy element tablicy, budować listę id, a następnie zapytać go z any- operator powstrzymywanie ?|:

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

Niestety, nie może indeks wyrażenie, które ma pod-zapytanie w nim ty. Jeśli chcesz indeksować to trzeba utworzyć funkcję do niego:

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)); 

Po tym, można wyszukać identyfikatory tak:

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

Uwaga: Kiedyś dot notation/computed field tutaj, ale nie musisz.

3. Ale w tym momencie nie musisz trzymać się json [b]: masz prostą tablicę tekstową, która jest obsługiwana przez 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)); 

i kwerendy pola obliczoną z operatorem tablicy nakładania &&:

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

Uwaga: Z mojego testowania wewnętrznego, to ostatnie rozwiązanie jest obliczana z wyższymi kosztami niż wariant jsonb, ale w rzeczywistości jest to szybsze niż to, trochę. Jeśli wydajność naprawdę ma dla ciebie znaczenie, powinieneś przetestować oba.

+1

Oto inne podejście: http://dba.stackexchange.com/questions/130699/postgresql-json-query-array-against-multiple-values ​​ – Chrizt0f

+0

@ Chrizt0f to jest moje 1. podejście również ("DOWOLNE" może być wyrażone przez wyrażenia "OR"). Zwykle trudno jest powiązać "jsonb []" w aplikacjach klienckich, ale jeśli OP (lub ktokolwiek, kto jest tym zainteresowany) może to zrobić, jest to również prawidłowe rozwiązanie - ale pamiętaj, że będzie używać tego indeksu kilka razy, więc mój Oryginalna notatka nadal obowiązuje (* Jeśli masz małą (i naprawioną) (sic!) liczba identyfikatorów do zapytania *) - ale przy "KAŻDYM" wygodniej jest dostarczać nie ustaloną liczbę identyfikatorów OFC. – pozs

4

znaleźć obejście:
where data::text similar to '%("id": "145119603"|"id": "1884595530")%'

+0

chociaż powoduje to wyszukiwanie pełnotekstowe na skan, to jest zgrabne – AnthonyJClink

Powiązane problemy