Seria muito mais eficiente armazenar seus valores em um esquema normalizado. Dito isto, você também pode fazê-lo funcionar com sua configuração atual.
Premissas
Assumindo esta definição de tabela:
CREATE TABLE tbl (tbl_id int, usr jsonb);
"usuário" é uma palavra reservada e requer que aspas duplas sejam usadas como nome da coluna. Não faça isso. Eu uso em usr
vez disso.
Inquerir
A consulta não é tão trivial quanto os comentários (agora excluídos) fizeram parecer:
SELECT t.tbl_id, obj.val->>'count' AS count
FROM tbl t
JOIN LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE t.usr @> '[{"_id":"1"}]';
Existem 3 etapas básicas :
1. Identifique linhas qualificadas baratas
WHERE t.usr @> '[{"_id":"1"}]'
identifica linhas com objeto correspondente na matriz JSON. A expressão pode usar um índice GIN genérico na jsonb
coluna ou um com a classe de operador mais especializada jsonb_path_ops
:
CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);
A WHERE
cláusula adicionada é logicamente redundante , mas é necessária para usar o índice. A expressão na cláusula de junção impõe a mesma condição, mas somente após desinvestir a matriz em todas as linhas qualificadas até o momento. Com o suporte ao índice, o Postgres processa apenas linhas que contêm um objeto qualificado para começar. Não importa muito com tabelas pequenas, faz uma enorme diferença com tabelas grandes e com poucas linhas de qualificação.
Relacionado:
2. Identifique os objetos correspondentes na matriz
Desnaturar com jsonb_array_elements()
. ( unnest()
só é bom para os tipos de array do Postgres.) Como estamos interessados apenas na correspondência de objetos, filtre a condição de junção imediatamente.
Relacionado:
3. Extrair valor para chave aninhada 'count'
Depois de objetos de qualificação foram extraídos, simplesmente: obj.val->>'count'
.
obj(value)
vem isso? Está noLATERAL JOIN
, nojsonb_array_elements
ou em outro lugar?JOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)
e issoobj(value)
é um alias de tabela e coluna? Neste exemplo, seobj
é um alias de tabela, para que é um alias? O conjunto retornou dejsonb_array_elements
?JOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'
teve o mesmo efeito (depois de atualizar a instrução select para usar emvalue
vez deval
). Parece quejsonb_array_elements(t.usr)
retorna uma tabela com apenas uma coluna. O postgres é inteligente e percebe queobj ->>
é o mesmoobj.val ->>
?