🧚 Écoute ! Beekeeper Studio est une interface de base de données rapide, moderne et open source Télécharger
23 mars 2025 Par Matthew Rathbone

PostgreSQL offre un support puissant pour stocker et interroger des données JSON grâce à ses types de données json et jsonb. Le type jsonb est particulièrement utile car il stocke les données dans un format binaire, ce qui permet une indexation et des requêtes plus efficaces que le type json, basé sur du texte.

Dans ce tutoriel, on va explorer les opérations JSON les plus courantes dans PostgreSQL avec des exemples pratiques que tu pourras utiliser dans tes applications.

Créer des données JSON

Commençons par créer un tableau avec une colonne jsonb et y insérer quelques données d’exemple :

CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    info JSONB
);

-- Insert a customer with basic information
INSERT INTO customers (info) VALUES (
    '{"name": "Alice Smith", "email": "alice@example.com", "age": 32, "addresses": [
        {"type": "home", "city": "San Francisco", "state": "CA"}, 
        {"type": "work", "city": "Oakland", "state": "CA"}
     ]}'
);

-- Insert another customer
INSERT INTO customers (info) VALUES (
    '{"name": "Bob Johnson", "email": "bob@example.com", "age": 45, "addresses": [
        {"type": "home", "city": "Seattle", "state": "WA"}
     ], "orders": [101, 102, 103]}'
);

Opérations JSON de base

Récupérer le document JSON complet

SELECT info FROM customers WHERE id = 1;

Résultat :

{
  "age": 32,
  "name": "Alice Smith",
  "email": "alice@example.com",
  "addresses": [
    {"city": "San Francisco", "type": "home", "state": "CA"},
    {"city": "Oakland", "type": "work", "state": "CA"}
  ]
}

Extraire des valeurs du JSON

PostgreSQL propose plusieurs opérateurs pour extraire des valeurs du JSON :

Extraire un champ précis avec l’opérateur -> (renvoie du JSON)

-- Get the name field as JSON
SELECT info -> 'name' FROM customers;

Résultat :

"Alice Smith"
"Bob Johnson"

Extraire un champ précis avec l’opérateur -» (renvoie du texte)

-- Get the name field as text
SELECT info ->> 'name' AS customer_name FROM customers;

Résultat :

customer_name
----------------
Alice Smith
Bob Johnson

Accéder aux objets imbriqués

-- Getting the first address (array element 0) city
SELECT info -> 'addresses' -> 0 ->> 'city' AS home_city FROM customers;

Résultat :

home_city
------------
San Francisco
Seattle

Utiliser l’opérateur #> pour accéder à un chemin

-- Using the path syntax to get the same value
SELECT info #> '{addresses,0,city}' FROM customers;

Résultat :

"San Francisco"
"Seattle"

Utiliser l’opérateur #» pour accéder à un chemin en texte

-- Using the path syntax to get the same value as text
SELECT info #>> '{addresses,0,city}' AS home_city FROM customers;

Résultat :

home_city
------------
San Francisco
Seattle

Modifier des données JSON

PostgreSQL fournit plusieurs fonctions pour modifier des données JSON :

Ajouter un champ avec jsonb_set

-- Add a new field 'premium_customer' to a customer
UPDATE customers
SET info = jsonb_set(info, '{premium_customer}', 'true')
WHERE id = 1;

Supprimer un champ avec l’opérateur -

-- Remove the premium_customer field
UPDATE customers
SET info = info - 'premium_customer'
WHERE id = 1;

Fusionner des objets JSON avec ||

-- Add multiple fields by merging objects
UPDATE customers
SET info = info || '{"status": "active", "last_login": "2025-03-23"}'::jsonb
WHERE id = 1;

Mettre à jour un champ imbriqué

-- Update a nested field (home address state)
UPDATE customers
SET info = jsonb_set(
    info, 
    '{addresses,0,state}', 
    '"NY"'::jsonb
)
WHERE id = 1;

Interroger des tableaux JSON

Travailler avec des tableaux JSON est une opération courante :

Obtenir la longueur d’un tableau

-- Get the number of addresses for each customer
SELECT 
    info ->> 'name' AS customer_name,
    jsonb_array_length(info -> 'addresses') AS address_count
FROM customers;

Résultat :

customer_name  | address_count
---------------+--------------
Alice Smith    | 2
Bob Johnson    | 1

Extraire des éléments précis d’un tableau

-- Get the second address (index 1) for Alice
SELECT info -> 'addresses' -> 1 FROM customers WHERE id = 1;

Résultat :

{"city": "Oakland", "type": "work", "state": "CA"}

Désimbriquer des tableaux pour interroger chaque élément

-- Unnest the addresses array to query individual addresses
SELECT 
    c.id,
    c.info ->> 'name' AS customer_name,
    jsonb_array_elements(c.info -> 'addresses') AS address
FROM customers c;

Résultat :

id | customer_name | address
---+---------------+------------------------------------------------------
1  | Alice Smith   | {"city": "San Francisco", "type": "home", "state": "NY"}
1  | Alice Smith   | {"city": "Oakland", "type": "work", "state": "CA"}
2  | Bob Johnson   | {"city": "Seattle", "type": "home", "state": "WA"}

Filtrer avec des tableaux désimbriqués

-- Find customers with addresses in CA
SELECT DISTINCT
    c.id,
    c.info ->> 'name' AS customer_name
FROM customers c,
     jsonb_array_elements(c.info -> 'addresses') AS addr
WHERE addr ->> 'state' = 'CA';

Résultat :

id | customer_name
---+--------------
1  | Alice Smith

Vérifier des clés et des valeurs

Vérifier si une clé existe

-- Find customers who have the 'orders' key
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info ? 'orders';

Résultat :

id | customer_name
---+--------------
2  | Bob Johnson

Rechercher des valeurs dans des tableaux

-- Find customers with a specific order number
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info -> 'orders' ? '101';

Résultat :

id | customer_name
---+--------------
2  | Bob Johnson

Vérifier si un élément du tableau correspond

-- Find customers who have an address in Oakland (using path operators)
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info @> '{"addresses": [{"city": "Oakland"}]}';

Résultat :

id | customer_name
---+--------------
1  | Alice Smith

Indexer des données JSON

Pour les bases de données de production avec de gros volumes de JSON, une bonne indexation est indispensable :

Créer un index GIN pour les requêtes de contenance

-- Create a GIN index for faster containment operations
CREATE INDEX idx_customers_info ON customers USING GIN (info);

Créer un index dédié à un champ JSON

-- Create an index on the 'email' field for fast lookups
CREATE INDEX idx_customers_email ON customers ((info ->> 'email'));

Utiliser des champs indexés dans les requêtes

-- This query can use the index we created above
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info ->> 'email' = 'alice@example.com';

Convertir entre JSON et tables

Convertir du JSON en lignes (jsonb_to_record)

-- Extract JSON fields into a tabular structure
SELECT 
    id,
    rec.name,
    rec.email,
    rec.age
FROM 
    customers,
    jsonb_to_record(info) AS rec(
        name text,
        email text,
        age int
    );

Résultat :

id | name         | email             | age
---+--------------+-------------------+-----
1  | Alice Smith  | alice@example.com | 32
2  | Bob Johnson  | bob@example.com   | 45

Convertir des tableaux imbriqués en tables (jsonb_to_recordset)

-- Extract addresses from all customers into a table
SELECT 
    c.id,
    c.info ->> 'name' AS customer_name,
    addr.type AS address_type,
    addr.city,
    addr.state
FROM 
    customers c,
    jsonb_to_recordset(c.info -> 'addresses') AS addr(
        type text,
        city text,
        state text
    );

Résultat :

id | customer_name | address_type | city          | state
---+---------------+--------------+---------------+------
1  | Alice Smith   | home         | San Francisco | NY
1  | Alice Smith   | work         | Oakland       | CA
2  | Bob Johnson   | home         | Seattle       | WA

Convertir des résultats de requête en JSON

-- Aggregate customer orders into a JSON array
SELECT
    c.id,
    c.info ->> 'name' AS customer_name,
    json_agg(o.order_id) AS orders
FROM 
    customers c
    CROSS JOIN LATERAL (
        SELECT jsonb_array_elements_text(c.info -> 'orders') AS order_id
    ) o
GROUP BY c.id, c.info ->> 'name';

Résultat :

id | customer_name | orders
---+---------------+----------
2  | Bob Johnson   | ["101", "102", "103"]

Considérations de performance

Quand tu travailles avec du JSON dans PostgreSQL, garde ces points de performance en tête :

  1. Utilise jsonb plutôt que json : le type jsonb offre de meilleures performances pour la plupart des opérations.

  2. Indexe de façon stratégique : utilise des index GIN pour les requêtes de contenance, mais crée des index dédiés pour les champs souvent interrogés.

  3. Réfléchis bien avant de dénormaliser : même si le JSON permet de dénormaliser ton modèle de données, une imbrication excessive peut nuire aux performances des requêtes.

  4. Surveille tes schémas de requêtes : les expressions de chemin JSON complexes ou la désimbrication fréquente de gros tableaux peuvent coûter cher.

  5. Limite la taille des tableaux : les très gros tableaux JSON peuvent poser des problèmes de performance une fois désimbriqués.

  6. Pense à la projection : extrais uniquement les champs dont tu as besoin plutôt que de renvoyer tout le document JSON.

Conclusion

Les capacités JSON de PostgreSQL en font un excellent choix pour les applications qui doivent stocker et interroger des données semi-structurées. Avec les opérateurs et fonctions vus dans ce tutoriel, tu peux travailler efficacement avec du JSON tout en profitant de la puissance et de la fiabilité d’une base de données relationnelle mature.

Pour les modèles de données complexes, envisage une approche hybride : utilise des tables structurées pour les schémas fixes et les données souvent interrogées, et du JSON pour les données flexibles sans schéma ou les structures imbriquées difficiles à modéliser de façon relationnelle.

Envie d’essayer ces exemples toi-même ? Ouvre Beekeeper Studio et commence dès aujourd’hui à explorer les capacités JSON de PostgreSQL.

Beekeeper Studio est une interface de base de données gratuite & open source

Le meilleur outil de requêtes & éditeur SQL que j’aie jamais utilisé. Il m’offre tout ce dont j’ai besoin pour gérer ma base de données. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio est rapide, intuitif et facile à utiliser. Beekeeper prend en charge plein de bases de données et fonctionne parfaitement sous Windows, Mac et Linux.

La version Linux de Beekeeper est 100% complète : rien de bâclé, aucun compromis sur les fonctionnalités.

Ce que les utilisateurs disent de Beekeeper Studio

★★★★★
« Beekeeper Studio a complètement remplacé mon ancien workflow SQL. C’est rapide, intuitif, et ça rend le travail sur les bases de données à nouveau agréable. »
— Alex K., développeur base de données
★★★★★
« J’ai essayé plein d’interfaces de base de données, mais Beekeeper trouve l’équilibre parfait entre fonctionnalités et simplicité. Ça marche, tout simplement. »
— Sarah M., ingénieure full stack