PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come interrogare gli array jsonb con l'operatore IN

Risposta breve

Puoi usare la funzione jsonb_array_elements() in un join laterale e usa il suo risultato value in espressioni complesse nel WHERE clausola:

SELECT t.* 
FROM test t
CROSS JOIN jsonb_array_elements(test_content)
WHERE value->>'label' IN ('b', 'd')
AND value->>'label1' IN ('2', '3')

Distinto

La query può restituire righe duplicate quando le condizioni di filtro sono soddisfatte in più di un elemento dell'array in una singola riga, ad es.

SELECT t.* 
FROM test t
CROSS JOIN jsonb_array_elements(test_content)
WHERE value->>'label' IN ('a', 'b')

                  id                  |                          test_content                          
--------------------------------------+----------------------------------------------------------------
 aa82a8b8-33ef-4937-bd8c-8a4b40960f18 | [{"label": "a", "label1": "1"}, {"label": "b", "label1": "2"}]
 aa82a8b8-33ef-4937-bd8c-8a4b40960f18 | [{"label": "a", "label1": "1"}, {"label": "b", "label1": "2"}]
(2 rows)    

Quindi può essere ragionevole usare DISTINCT nel SELECT elenco:

SELECT DISTINCT t.* 
FROM test t
CROSS JOIN jsonb_array_elements(test_content)
WHERE value->>'label' IN ('a', 'b')

o EXISTS nel WHERE clausola, che potrebbe essere un po' più veloce:

SELECT t.*
FROM test t
WHERE EXISTS (
    SELECT 
    FROM jsonb_array_elements(test_content)
    WHERE value->>'label' IN ('a', 'b')
    )

Puoi anche selezionare elementi dell'array corrispondenti nei casi in cui queste informazioni sono necessarie:

SELECT id, value
FROM test t
CROSS JOIN jsonb_array_elements(test_content)
WHERE value->>'label' IN ('a', 'b')

                  id                  |             value             
--------------------------------------+-------------------------------
 aa82a8b8-33ef-4937-bd8c-8a4b40960f18 | {"label": "a", "label1": "1"}
 aa82a8b8-33ef-4937-bd8c-8a4b40960f18 | {"label": "b", "label1": "2"}
(2 rows)

Prestazioni

Il jsonb_array_elements() la funzione è costosa. Per le tabelle più grandi l'uso della funzione può essere discutibile a causa del pesante carico del server e del lungo tempo di esecuzione di una query.

Mentre un indice GIN può essere utilizzato per query con @> operatore:

CREATE INDEX ON test USING GIN (test_content)

nel caso della funzione ciò non è possibile. Le query supportate dall'indice possono essere fino a diverse decine di volte più veloci di quelle che utilizzano la funzione.