Sería mucho más eficiente almacenar sus valores en un esquema normalizado. Dicho esto, también puedes hacer que funcione con tu configuración actual.
Supuestos
Suponiendo esta definición de tabla:
CREATE TABLE tbl (tbl_id int, usr jsonb);
"usuario" es una palabra reservada y requeriría comillas dobles para usar como nombre de columna. No hagas eso. Yo uso usr
en su lugar.
Consulta
La consulta no es tan trivial como los comentarios (ahora eliminados) lo hicieron 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"}]';
Hay 3 pasos básicos :
1. Identificar filas calificadas a bajo costo
WHERE t.usr @> '[{"_id":"1"}]'
identifica filas con objetos coincidentes en la matriz JSON. La expresión puede usar un índice GIN genérico en la jsonb
columna, o uno con la clase de operador más especializada jsonb_path_ops
:
CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);
La WHERE
cláusula agregada es lógicamente redundante , pero se requiere para usar el índice. La expresión en la cláusula de unión impone la misma condición pero solo después de anular la matriz en cada fila que califica hasta ahora. Con el soporte de índice, Postgres solo procesa filas que contienen un objeto calificado para empezar. No importa mucho con tablas pequeñas, hace una gran diferencia con tablas grandes y solo unas pocas filas calificadas.
Relacionado:
2. Identifique los objetos coincidentes en la matriz
Unnest con jsonb_array_elements()
. ( unnest()
solo es bueno para los tipos de matriz de Postgres). Dado que solo estamos interesados en la coincidencia de objetos, filtre la condición de unión de inmediato.
Relacionado:
3. Extraer valor para clave anidada 'count'
Después de los objetos que califican han sido extraídos, simplemente: obj.val->>'count'
.
obj(value)
viene el? ¿Está en elLATERAL JOIN
, eljsonb_array_elements
o en otro lugar?