🧚 Ascolta! Beekeeper Studio è una GUI per database veloce, moderna e open source Scarica
23 marzo 2025 Di Matthew Rathbone

PostgreSQL offre un supporto potente per archiviare e interrogare dati JSON tramite i tipi di dato json e jsonb. Il tipo jsonb è particolarmente utile perché memorizza i dati in formato binario, consentendo indicizzazione e query più efficienti rispetto al tipo testuale json.

In questo tutorial esploreremo le operazioni JSON più comuni in PostgreSQL con esempi pratici che puoi usare nelle tue applicazioni.

Creare dati JSON

Iniziamo creando una tabella con una colonna jsonb e inserendo alcuni dati di esempio:

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]}'
);

Operazioni JSON di base

Recuperare l'intero documento JSON

SELECT info FROM customers WHERE id = 1;

Risultato:

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

Estrarre valori da JSON

PostgreSQL offre diversi operatori per estrarre valori da JSON:

Estrarre un campo specifico con l'operatore -> (restituisce JSON)

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

Risultato:

"Alice Smith"
"Bob Johnson"

Estrarre un campo specifico con l'operatore -» (restituisce testo)

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

Risultato:

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

Accedere agli oggetti annidati

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

Risultato:

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

Usare l'operatore #> per l'accesso tramite percorso

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

Risultato:

"San Francisco"
"Seattle"

Usare l'operatore #» per l'accesso tramite percorso come testo

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

Risultato:

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

Modificare dati JSON

PostgreSQL fornisce diverse funzioni per modificare i dati JSON:

Aggiungere un campo con jsonb_set

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

Rimuovere un campo con l'operatore -

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

Unire oggetti JSON con ||

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

Aggiornare un campo annidato

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

Interrogare array JSON

Lavorare con gli array JSON è un'operazione comune:

Ottenere la lunghezza di un array

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

Risultato:

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

Estrarre elementi specifici di un array

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

Risultato:

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

Espandere gli array per interrogare i singoli elementi

-- 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;

Risultato:

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"}

Filtrare con array espansi

-- 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';

Risultato:

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

Verificare chiavi e valori

Verificare se una chiave esiste

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

Risultato:

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

Verificare la presenza di valori negli array

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

Risultato:

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

Verificare se un elemento dell'array corrisponde

-- 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"}]}';

Risultato:

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

Indicizzare dati JSON

Per database in produzione con grandi dataset JSON, un'indicizzazione adeguata è essenziale:

Creare un indice GIN per query di contenimento

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

Creare un indice specifico per un campo JSON

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

Usare campi indicizzati nelle query

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

Conversione tra JSON e tabelle

Convertire JSON in righe (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
    );

Risultato:

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

Convertire array annidati in tabelle (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
    );

Risultato:

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

Convertire i risultati delle query in 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';

Risultato:

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

Considerazioni sulle prestazioni

Quando lavori con JSON in PostgreSQL, tieni a mente queste considerazioni sulle prestazioni:

  1. Usa jsonb invece di json: il tipo jsonb offre prestazioni migliori per la maggior parte delle operazioni.

  2. Indicizza in modo strategico: usa indici GIN per le query di contenimento, ma crea indici specifici per i campi interrogati spesso.

  3. Valuta con attenzione la denormalizzazione: anche se JSON ti permette di denormalizzare il modello dati, un annidamento eccessivo può influire sulle prestazioni delle query.

  4. Osserva i pattern delle query: espressioni di percorso JSON complesse o l'espansione frequente di array grandi possono essere operazioni costose.

  5. Limita la dimensione degli array: array JSON molto grandi possono causare problemi di prestazioni quando vengono espansi.

  6. Usa la proiezione: estrai solo i campi che ti servono invece di restituire l'intero documento JSON.

Conclusione

Le funzionalità JSON di PostgreSQL lo rendono una scelta eccellente per le applicazioni che devono archiviare e interrogare dati semi-strutturati. Con gli operatori e le funzioni visti in questo tutorial puoi lavorare in modo efficace con i dati JSON, sfruttando al tempo stesso la potenza e l'affidabilità di un database relazionale maturo.

Per modelli dati complessi, valuta un approccio ibrido: usa tabelle strutturate per schemi fissi e dati interrogati spesso, e JSON per dati flessibili senza schema o strutture annidate che sarebbe scomodo modellare in modo relazionale.

Vuoi provare questi esempi di persona? Apri Beekeeper Studio e inizia oggi a esplorare le funzionalità JSON di PostgreSQL.

Beekeeper Studio è una GUI per database gratuita & open source

Il miglior strumento per query & editor SQL che abbia mai usato. Offre tutto ciò che mi serve per gestire il mio database. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio è veloce, intuitivo e facile da usare. Beekeeper supporta tantissimi database e funziona alla grande su Windows, Mac e Linux.

La versione Linux di Beekeeper è completa al 100%, senza tagli e senza compromessi sulle funzionalità.

Cosa dicono gli utenti di Beekeeper Studio

★★★★★
"Beekeeper Studio ha sostituito completamente il mio vecchio workflow SQL. È veloce, intuitivo e rende di nuovo piacevole lavorare con i database."
— Alex K., Database Developer
★★★★★
"Ho provato molte GUI per database, ma Beekeeper trova il perfetto equilibrio tra funzionalità e semplicità. Funziona e basta."
— Sarah M., Full Stack Engineer

Pronto a migliorare il tuo workflow SQL?

download Scarica gratis