</>
Plan du cours — 36/64

jsonb : des documents dans une base relationnelle

Avancé

jsonb stocke du JSON dans un format binaire indexable : idéal pour des attributs variables, des payloads d'événements ou des configurations, sans quitter le modèle relationnel.

CREATE TABLE evenements (
    id      bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    type    text  NOT NULL,
    donnees jsonb NOT NULL
);

INSERT INTO evenements (type, donnees)
VALUES ('achat', '{"client": {"id": 42, "pays": "FR"}, "articles": [{"sku": "A1", "qte": 2}]}');

Les opérateurs#

OpérateurRôleExemple
->Extrait un champ (résultat jsonb)donnees -> 'client'
->>Extrait un champ en textedonnees -> 'client' ->> 'pays'
#>>Extrait par chemin, en textedonnees #>> '{client,id}'
@>Contientdonnees @> '{"type": "achat"}'
?Une clé existedonnees ? 'client'
jsonb_path_existsRequête JSONPathjsonb_path_exists(donnees, '$.articles[*] ? (@.qte > 1)')
SELECT donnees -> 'client' ->> 'pays' AS pays, count(*)
FROM   evenements
WHERE  donnees @> '{"client": {"pays": "FR"}}'
GROUP  BY 1;

-- Modifier un champ
UPDATE evenements SET donnees = jsonb_set(donnees, '{client,pays}', '"BE"') WHERE id = 1;

Indexer#

CREATE INDEX evenements_donnees_gin ON evenements USING gin (donnees);                 -- @>, ?, etc.
CREATE INDEX evenements_pays_idx    ON evenements ((donnees #>> '{client,pays}'));     -- un champ précis

jsonb ou colonnes ?#

  • Colonnes : données stables, requêtées, jointes, contraintes (clés étrangères, NOT NULL, types).
  • jsonb : attributs variables ou peu utilisés pour filtrer, données reçues d'un tiers à conserver telles quelles.

Piège : un jsonb « fourre-tout » perd les garanties du relationnel : pas de clé étrangère, pas de type imposé, statistiques du planificateur limitées. Extrayez en colonnes les champs dont vous filtrez, joignez ou triez souvent (éventuellement en colonne générée).