Se JSONB è come un baule magico dove buttiamo i dati, allora || e jsonb_concat() sono gli attrezzi che ci permettono di unire questi bauli o cambiare quello che c'è dentro. Nella vita reale, ti può capitare di dover unire più oggetti JSON, aggiungere dati da uno all'altro o fondere array in una sola lista.
Per esempio, immagina di avere due oggetti JSONB:
{"nome": "Alice", "età": 25}
e
{"città": "Wonderland", "hobby": ["lettura", "scacchi"]}
Vuoi ottenere:
{"nome": "Alice", "età": 25, "città": "Wonderland", "hobby": ["lettura", "scacchi"]}
Oppure unire due array JSONB:
[1, 2, 3]
e
[4, 5, 6]
così che il risultato sia:
[1, 2, 3, 4, 5, 6]
Tutto questo si fa con || o jsonb_concat(). Vediamo come funziona.
L'operatore || per unire JSONB
L'operatore || ti permette di unire due oggetti o array JSONB in PostgreSQL. È semplice, veloce e facilissimo da usare. Ecco le regole base:
- Se unisci due oggetti JSONB, l'oggetto risultante avrà tutte le chiavi e i valori di entrambi.
- Se le chiavi si sovrappongono, il valore dell'operando di destra sostituisce quello di sinistra.
- Se unisci array JSONB, gli elementi dell'array di sinistra e di destra vengono messi insieme in un unico array.
Esempio 1: Unione di due oggetti JSONB
SELECT '{"nome": "Alice", "età": 25}'::jsonb || '{"città": "Wonderland", "hobby": ["lettura", "scacchi"]}'::jsonb AS oggetto_unito;
Risultato:
{"nome": "Alice", "età": 25, "città": "Wonderland", "hobby": ["lettura", "scacchi"]}
Esempio 2: Aggiornamento dei valori quando le chiavi coincidono
SELECT '{"nome": "Alice", "età": 25}'::jsonb || '{"età": 30, "città": "Wonderland"}'::jsonb AS oggetto_aggiornato;
Risultato:
{"nome": "Alice", "età": 30, "città": "Wonderland"}
Nota che il valore della chiave "età" dell'oggetto di destra ha sostituito quello di sinistra.
Esempio 3: Unione di array
SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS array_unito;
Risultato:
[1, 2, 3, 4, 5, 6]
La funzione jsonb_concat() per unire JSONB
La funzione jsonb_concat() funziona come l'operatore ||, ma è più flessibile se ti serve usarla in funzioni, trigger o query dinamiche. Prende due argomenti di tipo JSONB e restituisce il risultato unito.
Esempio: uso di jsonb_concat()
SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combinato;
Risultato:
{"a": 1, "b": 3, "c": 4}
Unione di oggetti e array: particolarità e dettagli
Quando unisci oggetti con chiavi che coincidono, ricorda che i valori dell'oggetto di destra hanno la precedenza.
Per esempio:
SELECT '{"chiave1": "valore1"}'::jsonb || '{"chiave1": "valore2"}'::jsonb AS risultato;
Risultato:
{"chiave1": "valore2"}
Se vuoi evitare la sovrascrittura dei valori, meglio mettere questi dati in chiavi diverse o usare un altro approccio (tipo un array).
Invece gli array vengono sempre uniti aggiungendo gli elementi dell'array di destra a quello di sinistra. Per esempio:
SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS risultato;
Risultato:
["a", "b", "c", "d"]
Se dentro l'array ci sono oggetti, l'ordine viene mantenuto:
SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS risultato;
Risultato:
[{"id": 1}, {"id": 2}, {"id": 3}]
Esempi pratici
Aggiornamento del profilo utente. Supponiamo di avere una tabella utenti dove i profili sono salvati in formato JSONB:
CREATE TABLE utenti (
id SERIAL PRIMARY KEY,
profilo JSONB
);
INSERT INTO utenti (profilo) VALUES ('{"nome": "Alice", "età": 25}');
Ora vogliamo aggiungere la città di residenza:
UPDATE utenti
SET profilo = profilo || '{"città": "Wonderland"}'
WHERE id = 1;
Risultato della query:
{"nome": "Alice", "età": 25, "città": "Wonderland"}
Unione dei dati sugli ordini. Mettiamo di avere una tabella ordini:
CREATE TABLE ordini (
id SERIAL PRIMARY KEY,
dettagli JSONB
);
INSERT INTO ordini (dettagli) VALUES ('{"articoli": [{"prodotto": "laptop", "quantità": 1}]}');
Ora aggiungiamo un altro prodotto all'ordine:
UPDATE ordini
SET dettagli = jsonb_set(
dettagli,
'{articoli}',
dettagli->'articoli' || '[{"prodotto": "mouse", "quantità": 2}]'::jsonb
)
WHERE id = 1;
Risultato della query:
{"articoli": [{"prodotto": "laptop", "quantità": 1}, {"prodotto": "mouse", "quantità": 2}]}
Differenze tra || e jsonb_concat()
Dal punto di vista funzionale, l'operatore || e la funzione jsonb_concat() sono identici. Usa || se scrivi query semplici, perché è più corto. La funzione jsonb_concat() è comoda quando ti serve chiamarla esplicitamente dentro un programma o un trigger.
Errori tipici e come evitarli
Errore: tentativo di unire tipi incompatibili.
SELECT '{"chiave": "valore"}'::jsonb || '["valore"]'::jsonb;
Risultato:
ERROR: cannot concatenate jsonb objects and arrays
Qui a sinistra c'è un oggetto, a destra un array — PostgreSQL non può unirli così. Per far funzionare l'operazione, entrambi gli operandi devono essere dello stesso tipo: o due oggetti, o due array.
Dimenticanza: mancanza di indici quando lavori con JSONB
Se filtri spesso i dati sui valori dentro i campi JSONB e non hai indici — le query possono diventare lentissime. Non è un errore classico, ma le conseguenze sulle performance si sentono. Ricordati di usare gli indici GIN:
CREATE INDEX idx_dati_profilo ON dipendenti USING gin(profilo);
GO TO FULL VERSION