Aktualizovat :S PostgreSQL 9.5 existuje několik jsonb
funkce manipulace v rámci samotného PostgreSQL (ale žádná pro json
; přetypování je nutné pro manipulaci s json
hodnoty).
Sloučení 2 (nebo více) objektů JSON (nebo zřetězení polí):
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]'
Takže nastavení jednoduchého klíče lze provést pomocí:
SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')
Kde <key>
by měl být řetězec a <value>
může být jakéhokoli typu to_jsonb()
přijímá.
Pro nastavení hodnoty hluboko v hierarchii JSON , jsonb_set()
lze použít funkci:
SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'
Úplný seznam parametrů jsonb_set()
:
jsonb_set(target jsonb,
path text[],
new_value jsonb,
create_missing boolean default true)
path
může obsahovat také indexy pole JSON a záporná celá čísla, která se tam objevují, se počítají od konce polí JSON. Neexistující, ale kladný index pole JSON však připojí prvek na konec pole:
SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'
Pro vložení do pole JSON (při zachování všech původních hodnot) , jsonb_insert()
lze použít funkci (ve verzi 9.6+; pouze tato funkce v této sekci ):
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]}]}'
Úplný seznam parametrů jsonb_insert()
:
jsonb_insert(target jsonb,
path text[],
new_value jsonb,
insert_after boolean default false)
Opět platí, že záporná celá čísla, která se objevují v path
počítat od konce polí JSON.
Takže např. připojení na konec pole JSON lze provést pomocí:
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
Tato funkce však funguje mírně odlišně (než jsonb_set()
), když path
v target
je klíč objektu JSON. V takovém případě přidá nový pár klíč–hodnota pro objekt JSON pouze tehdy, když se klíč nepoužívá. Pokud je použit, vyvolá chybu:
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
Odstranění klíče (nebo indexu) z objektu JSON (nebo z pole) lze provést pomocí -
operátor:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Odstranění hluboko v hierarchii JSON lze provést pomocí #-
operátor:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
Pro 9.4 , můžete použít upravenou verzi původní odpovědi (níže), ale místo agregace řetězce JSON můžete agregovat do objektu json přímo pomocí json_object_agg()
.
Původní odpověď :Je to možné (bez plpythonu nebo plv8) také v čistém SQL (ale potřebuje 9.3+, nebude fungovat s 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
Upravit :
Verze, která nastavuje více klíčů a hodnot:
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$;
Úprava 2 :jak poznamenal @ErwinBrandstetter, výše uvedené funkce fungují jako takzvaný UPSERT
(aktualizuje pole, pokud existuje, vloží, pokud neexistuje). Zde je varianta, která pouze 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$;
Úprava 3 :Zde je rekurzivní varianta, kterou lze nastavit (UPSERT
) hodnotu listu (a používá první funkci z této odpovědi), umístěnou na cestě klíče (kde klíče mohou odkazovat pouze na vnitřní objekty, vnitřní pole nejsou podporována):
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$;
Aktualizováno:Přidána funkce pro nahrazení existujícího klíče pole json jiným daným klíčem. Může se hodit při aktualizaci datových typů při migracích nebo jiných scénářích, jako je změna struktury dat.
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;
Aktualizovat :funkce jsou nyní zkomprimovány.