Aggiorna :Con PostgreSQL 9.5, ci sono alcuni jsonb
funzionalità di manipolazione all'interno di PostgreSQL stesso (ma nessuna per json
; i cast sono necessari per manipolare json
valori).
Unire 2 (o più) oggetti JSON (o concatenare array):
SELECT jsonb '{"a":1}' || jsonb '{"b":2}', -- will yield jsonb '{"a":1,"b":2}'
jsonb '["a",1]' || jsonb '["b",2]' -- will yield jsonb '["a",1,"b",2]'
Quindi, impostare una chiave semplice può essere fatto utilizzando:
SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')
Dove <key>
dovrebbe essere stringa e <value>
può essere di qualsiasi tipo to_jsonb()
accetta.
Per impostare un valore all'interno di una gerarchia JSON , il jsonb_set()
può essere utilizzata la funzione:
SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'
Elenco completo dei parametri di jsonb_set()
:
jsonb_set(target jsonb,
path text[],
new_value jsonb,
create_missing boolean default true)
path
può contenere anche indici di array JSON e numeri interi negativi che appaiono lì contano dalla fine degli array JSON. Tuttavia, un indice di matrice JSON non esistente ma positivo aggiungerà l'elemento alla fine della matrice:
SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'
Per l'inserimento nell'array JSON (conservando tutti i valori originali) , il jsonb_insert()
può essere utilizzata (in 9.6+; solo questa funzione, in questa sezione ):
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2')
-- will yield jsonb '{"a":[null,{"b":[2,1]}]}', and
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2', true)
-- will yield jsonb '{"a":[null,{"b":[1,2]}]}'
Elenco completo dei parametri di jsonb_insert()
:
jsonb_insert(target jsonb,
path text[],
new_value jsonb,
insert_after boolean default false)
Di nuovo, numeri interi negativi che appaiono in path
contare dalla fine degli array JSON.
Quindi, f.ex. l'aggiunta all'estremità di un array JSON può essere eseguita con:
SELECT jsonb_insert('{"a":[null,{"b":[1,2]}]}', '{a,1,b,-1}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}', and
Tuttavia, questa funzione funziona in modo leggermente diverso (rispetto a jsonb_set()
) quando il path
in target
è la chiave di un oggetto JSON. In tal caso, aggiungerà solo una nuova coppia chiave-valore per l'oggetto JSON quando la chiave non viene utilizzata. Se viene utilizzato, genererà un errore:
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,c}', jsonb '[2]')
-- will yield jsonb '{"a":[null,{"b":[1],"c":[2]}]}', but
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b}', jsonb '[2]')
-- will raise SQLSTATE 22023 (invalid_parameter_value): cannot replace existing key
Eliminazione di una chiave (o di un indice) da un oggetto JSON (o, da un array) può essere fatto con -
operatore:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Eliminazione, da una gerarchia JSON profonda può essere fatto con il #-
operatore:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
Per 9.4 , puoi utilizzare una versione modificata della risposta originale (sotto), ma invece di aggregare una stringa JSON, puoi aggregarla in un oggetto json direttamente con json_object_agg()
.
Risposta originale :È possibile (senza plpython o plv8) anche in puro SQL (ma necessita di 9.3+, non funzionerà con 9.2)
CREATE OR REPLACE FUNCTION "json_object_set_key"(
"json" json,
"key_to_set" TEXT,
"value_to_set" anyelement
)
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
FROM (SELECT *
FROM json_each("json")
WHERE "key" <> "key_to_set"
UNION ALL
SELECT "key_to_set", to_json("value_to_set")) AS "fields"
$function$;
SQLFiddle
Modifica :
Una versione che imposta più chiavi e valori:
CREATE OR REPLACE FUNCTION "json_object_set_keys"(
"json" json,
"keys_to_set" TEXT[],
"values_to_set" anyarray
)
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
FROM (SELECT *
FROM json_each("json")
WHERE "key" <> ALL ("keys_to_set")
UNION ALL
SELECT DISTINCT ON ("keys_to_set"["index"])
"keys_to_set"["index"],
CASE
WHEN "values_to_set"["index"] IS NULL THEN 'null'::json
ELSE to_json("values_to_set"["index"])
END
FROM generate_subscripts("keys_to_set", 1) AS "keys"("index")
JOIN generate_subscripts("values_to_set", 1) AS "values"("index")
USING ("index")) AS "fields"
$function$;
Modifica 2 :come ha notato @ErwinBrandstetter, queste funzioni sopra funzionano come un cosiddetto UPSERT
(aggiorna un campo se esiste, lo inserisce se non esiste). Ecco una variante, che solo UPDATE
:
CREATE OR REPLACE FUNCTION "json_object_update_key"(
"json" json,
"key_to_set" TEXT,
"value_to_set" anyelement
)
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT CASE
WHEN ("json" -> "key_to_set") IS NULL THEN "json"
ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
FROM (SELECT *
FROM json_each("json")
WHERE "key" <> "key_to_set"
UNION ALL
SELECT "key_to_set", to_json("value_to_set")) AS "fields")::json
END
$function$;
Modifica 3 :Ecco una variante ricorsiva, che può impostare (UPSERT
) un valore foglia (e utilizza la prima funzione di questa risposta), situato in un percorso chiave (dove le chiavi possono fare riferimento solo a oggetti interni, array interni non supportati):
CREATE OR REPLACE FUNCTION "json_object_set_path"(
"json" json,
"key_path" TEXT[],
"value_to_set" anyelement
)
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT CASE COALESCE(array_length("key_path", 1), 0)
WHEN 0 THEN to_json("value_to_set")
WHEN 1 THEN "json_object_set_key"("json", "key_path"[l], "value_to_set")
ELSE "json_object_set_key"(
"json",
"key_path"[l],
"json_object_set_path"(
COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
"key_path"[l+1:u],
"value_to_set"
)
)
END
FROM array_lower("key_path", 1) l,
array_upper("key_path", 1) u
$function$;
Aggiornato:aggiunta la funzione per sostituire la chiave di un campo json esistente con un'altra chiave specificata. Può essere utile per aggiornare i tipi di dati nelle migrazioni o in altri scenari come la modifica della struttura dei dati.
CREATE OR REPLACE FUNCTION json_object_replace_key(
json_value json,
existing_key text,
desired_key text)
RETURNS json AS
$BODY$
SELECT COALESCE(
(
SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}')
FROM (
SELECT *
FROM json_each(json_value)
WHERE key <> existing_key
UNION ALL
SELECT desired_key, json_value -> existing_key
) AS "fields"
-- WHERE value IS NOT NULL (Actually not required as the string_agg with value's being null will "discard" that entry)
),
'{}'
)::json
$BODY$
LANGUAGE sql IMMUTABLE STRICT
COST 100;
Aggiorna :le funzioni sono ora compattate.