JSONB și operatorii ->, ->>, @>, ? în PostgreSQL

JSONB, Array și tipuri avansate PostgreSQL 9.4+ (subscripting JSONB din PostgreSQL 14+)

Interoghează și filtrează documente binare JSONB folosind operatorii de extracție (->, ->>) și incluziune (@>, ?).

Sintaxă SQL
SELECT date_jsonb->>'cheie', date_jsonb->'obiect'->>'subcheie' FROM tabel WHERE date_jsonb @> '{"activ": true}';

Ce face JSONB și operatorii ->, ->>, @>, ?

PostgreSQL oferă două tipuri pentru stocarea documentelor JSON: json (care păstrează textul brut exact cum a fost primit) și jsonb (care descompune documentul într-un format binar optimizat, elimină spațiile inutile, ordonează cheile și suportă indexare GIN). În aproape toate aplicațiile se recomandă folosirea tipului JSONB.

Pentru navigarea în obiecte și vectori JSONB se folosesc operatorii -> (returnează tot un element jsonb, util pentru înlănțuire) și ->> (returnează valoarea ca text, utilă pentru afișare sau conversie la număr). Pentru filtrări rapide în clauza WHERE asistate de un index GIN, se folosesc operatorul de incluziune @> și operatorul de existență a cheii ?.

Clauze, operatori și argumente

Clauză / Operator Descriere
jsonb -> 'cheie' (sau -> index) Extrage câmpul obiectului sau elementul din array (de la 0) păstrând tipul de date jsonb (cu ghilimele pentru șiruri).
jsonb ->> 'cheie' (sau ->> index) Extrage câmpul obiectului sau elementul din array direct ca text (fără ghilimele JSON).
jsonb #> '{cale,subcale}' Extrage sub-obiectul jsonb aflat la calea specificată (sau ca text cu #>>).
jsonb @> '{"k": "v"}'::jsonb Operatorul de incluziune (contains): verifică dacă documentul din stânga conține structura JSONB din dreapta (indexabil GIN).
jsonb ? 'cheie' Verifică dacă șirul apare ca nume de cheie la nivelul curent (sau ca element într-un array JSONB).
jsonb ?| array / ?& array Verifică dacă există oricare (?|) sau toate (?&) cheile din tabloul de text specificat.

Exemple

Exemplul 1: Extragerea câmpurilor și filtrarea cu operatorul de incluziune @>

Selectăm produsele care au în coloana specificatii (de tip jsonb) atributul "memorie_ram": 32 și extragem procesorul ca text cu ->>.

SELECT id,
       denumire,
       specificatii->>'procesor' AS procesor,
       (specificatii->>'greutate_kg')::numeric AS greutate_kg
FROM produse
WHERE specificatii @> '{"memorie_ram": 32, "stocare": {"tip": "NVMe"}}'::jsonb;

Rezultat interogare

 id |      denumire       |   procesor   | greutate_kg 
----+---------------------+--------------+-------------
 12 | ProBook Ultra 16 M3 | Apple M3 Pro |        1.62
 19 | ThinkStation Dev 15 | Ryzen 9 7940 |        1.85
(2 rows)

Exemplul 2: Verificarea existenței unei chei și accesul prin subscripție nativă (PostgreSQL 14+)

Filtrăm utilizatorii care au cheia telefon_urgenta definită în profilul JSONB și citim orașul din sub-obiectul adresa.

SELECT id,
       email,
       profil['adresa']['oras'] #>> '{}' AS oras,
       profil->>'telefon_urgenta' AS telefon_urgenta
FROM utilizatori
WHERE profil ? 'telefon_urgenta';

Rezultat interogare

 id |          email          |   oras    | telefon_urgenta 
----+-------------------------+-----------+-----------------
 14 | andrei.popescu@firma.ro | București | +40722111222
 29 | elena.pm@exemplu.ro     | Cluj      | +40744333444
(2 rows)

Greșeli frecvente

  • Compararea cu un șir sau conversia la număr folosind -> în loc de ->>: expresia specificatii->'procesor' returnează un jsonb cu ghilimele incluse ("Apple M3 Pro"), în timp ce ->> returnează textul curat.
  • Filtrarea prin WHERE specificatii->>'memorie_ram' = '32' nu folosește un index GIN standard pe întreaga coloană specificatii; rescrie condiția ca WHERE specificatii @> '{"memorie_ram": 32}' pentru a beneficia de indexul GIN.

Comenzi și funcții înrudite