Sarebbe molto più efficiente archiviare i tuoi valori in uno schema normalizzato. Detto questo, puoi anche farlo funzionare con la tua configurazione attuale.
ipotesi
Supponendo questa definizione di tabella:
CREATE TABLE tbl (tbl_id int, usr jsonb);
"utente" è una parola riservata e richiederebbe una doppia virgoletta da utilizzare come nome di colonna. Non farlo. Io uso usr
invece.
domanda
La query non è banale come i commenti (ora eliminati) sembravano:
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"}]';
Ci sono 3 passaggi di base :
1. Identificare le file qualificanti a buon mercato
WHERE t.usr @> '[{"_id":"1"}]'
identifica le righe con l'oggetto corrispondente nell'array JSON. L'espressione può utilizzare un indice GIN generico sulla jsonb
colonna o uno con la classe operatore più specializzata jsonb_path_ops
:
CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);
La WHERE
clausola aggiunta è logicamente ridondante , ma è necessario per utilizzare l'indice. L'espressione nella clausola join impone la stessa condizione, ma solo dopo aver annullato l'intervallo dell'array in ogni riga fino a quel momento. Con il supporto dell'indice, Postgres elabora solo le righe che contengono un oggetto idoneo. Non importa molto con i tavoli piccoli, fa una grande differenza con i tavoli grandi e solo poche righe qualificanti.
Relazionato:
2. Identificare gli oggetti corrispondenti nell'array
Unnest with jsonb_array_elements()
. ( unnest()
è utile solo per i tipi di array Postgres.) Dato che siamo interessati solo alla corrispondenza effettiva degli oggetti, filtra subito la condizione di join.
Relazionato:
3. Estrarre il valore per la chiave nidificata 'count'
Dopo di ottenimento sono stati estratti, semplicemente: obj.val->>'count'
.
obj(value)
viene? È sulLATERAL JOIN
, iljsonb_array_elements
o da qualche altra parte?