PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como consultar matrizes jsonb com o operador IN

Resposta curta


Você pode usar a função jsonb_array_elements() em uma junção lateral e use seu resultado value em expressões complexas no WHERE cláusula:
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


A consulta pode retornar linhas duplicadas quando as condições do filtro são atendidas em mais de um elemento da matriz em uma única linha, por exemplo.
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)    

Portanto, pode ser razoável usar DISTINCT no SELECT Lista:
SELECT DISTINCT t.* 
FROM test t
CROSS JOIN jsonb_array_elements(test_content)
WHERE value->>'label' IN ('a', 'b')

ou EXISTS no WHERE cláusula, que pode ser um pouco mais rápida:
SELECT t.*
FROM test t
WHERE EXISTS (
    SELECT 
    FROM jsonb_array_elements(test_content)
    WHERE value->>'label' IN ('a', 'b')
    )

Você também pode selecionar elementos de matriz correspondentes nos casos em que essas informações são necessárias:
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)

Desempenho


O jsonb_array_elements() função é cara. Para tabelas maiores, o uso da função pode ser questionável devido à carga pesada do servidor e ao longo tempo de execução de uma consulta.

Enquanto um índice GIN pode ser usado para consultas com o @> operador:
CREATE INDEX ON test USING GIN (test_content)

no caso da função isso não é possível. As consultas suportadas pelo índice podem ser até várias dezenas de vezes mais rápidas do que aquelas que usam a função.