Eu tenho uma tabela JSON muito simples que preencho com alguns dados de amostra:
CREATE TABLE jsonthings(d JSONB NOT NULL);
INSERT INTO jsonthings VALUES ('{"name":"First","tags":["foo"]}');
INSERT INTO jsonthings VALUES ('{"name":"Second","tags":["foo","bar"]}');
INSERT INTO jsonthings VALUES ('{"name":"Third","tags":["bar","baz"]}');
INSERT INTO jsonthings VALUES ('{"name":"Fourth","tags":["baz"]}');
CREATE INDEX ON jsonthings USING GIN(d);
E estou tentando usar o índice ao executar um arquivo SELECT
. Um simples SELECT
para obter as linhas onde o valor é um único item funciona muito bem:
SELECT d FROM jsonthings WHERE d @> '{"name":"First"}';
Mas ao tentar executar uma consulta que corresponda a mais de um valor name
, não consigo descobrir como usar o índice. Eu tentei:
SELECT d FROM jsonthings WHERE d->>'name' = ANY(ARRAY['First', 'Second']);
SELECT d FROM jsonthings WHERE d->'name' ?| ARRAY['First', 'Second'];
SELECT d FROM jsonthings WHERE d#>'{name}' ?| ARRAY['First','Second'];
e todos eles mostram uma varredura sequencial da tabela (estou usando enable_seqscan=false
para forçar o uso do índice, se possível). Existe alguma maneira de reescrever a consulta para que ela use um índice? Estou ciente de que poderia fazer:
SELECT * FROM jsonthings WHERE d @> '{"name":"First"}' OR d @> '{"name":"Second"}';
mas então eu tenho uma consulta de comprimento variável e estou passando por JDBC, então perderia os benefícios da consulta sendo um PreparedStatement.
Também estou interessado em ver uma consulta semelhante em qualquer um dos vários itens da tags
chave, por exemplo:
SELECT d FROM jsonthings WHERE d @> '{"tags":["foo"]}' OR d @> '{"tags":["bar"]}';
mas usando um ARRAY
em vez de várias condições e usando um índice.
Isso está no PostgreSql 9.4.
Esta é uma resposta à resposta fornecida por Mladen. Não tenho reputação suficiente para deixar um comentário, mas queria responder porque parece que a consulta pode estar incorreta e estava me confundindo e pode confundir outras pessoas no futuro.
Você menciona usar:
Para recuperar quaisquer entradas que tenham
First
ouSecond
como nome, no entanto, isso não parece funcionar para mim emPostgreSQL 9.4.4
:Parece que a consulta acima está tentando recuperar entradas onde o
name
atributo contém o array["First", "Second"]
.Se eu criar tal entrada:
E então tente a consulta novamente, ela retorna um resultado:
No entanto, isso é diferente da pergunta feita pelo postador original, que era como usar um índice ao consultar entradas em que o
name
atributo eraFirst
ouSecond
:Eu queria fornecer isso aqui para que outras pessoas não pensem que é possível realizar uma consulta OR com JSON fornecendo
"name": ["First", "Second"]
, pois é enganoso.De docs ( http://www.postgresql.org/docs/9.4/static/datatype-json.html ) tente usar o índice de expressão: