Perbarui :Dengan PostgreSQL 9.5, ada beberapa jsonb
fungsi manipulasi dalam PostgreSQL itu sendiri (tetapi tidak untuk json
; gips diperlukan untuk memanipulasi json
nilai).
Menggabungkan 2 (atau lebih) objek JSON (atau menggabungkan 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]'
Jadi, menyetel kunci sederhana dapat dilakukan dengan menggunakan:
SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')
Dimana <key>
harus berupa string, dan <value>
bisa apa saja jenis to_jsonb()
menerima.
Untuk menyetel nilai jauh di dalam hierarki JSON , jsonb_set()
fungsi yang dapat digunakan:
SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'
Daftar parameter lengkap jsonb_set()
:
jsonb_set(target jsonb,
path text[],
new_value jsonb,
create_missing boolean default true)
path
dapat berisi indeks array JSON juga &bilangan bulat negatif yang muncul di sana dihitung dari akhir array JSON. Namun, indeks array JSON yang tidak ada tetapi positif akan menambahkan elemen ke akhir array:
SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'
Untuk memasukkan ke dalam larik JSON (sambil mempertahankan semua nilai asli) , jsonb_insert()
fungsi dapat digunakan (di 9.6+; hanya fungsi ini, di bagian ini ):
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]}]}'
Daftar parameter lengkap jsonb_insert()
:
jsonb_insert(target jsonb,
path text[],
new_value jsonb,
insert_after boolean default false)
Sekali lagi, bilangan bulat negatif yang muncul di path
hitung dari akhir array JSON.
Jadi, f.ex. menambahkan ke akhir array JSON dapat dilakukan dengan:
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
Namun, fungsi ini bekerja sedikit berbeda (dari jsonb_set()
) ketika path
di target
adalah kunci objek JSON. Dalam hal ini, itu hanya akan menambahkan pasangan nilai kunci baru untuk objek JSON saat kunci tidak digunakan. Jika digunakan, itu akan menimbulkan kesalahan:
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
Menghapus kunci (atau indeks) dari objek JSON (atau, dari array) dapat dilakukan dengan -
operator:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Menghapus, dari dalam hierarki JSON dapat dilakukan dengan #-
operator:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
Untuk 9,4 , Anda dapat menggunakan versi modifikasi dari jawaban asli (di bawah), tetapi alih-alih menggabungkan string JSON, Anda dapat menggabungkan menjadi objek json secara langsung dengan json_object_agg()
.
Jawaban asli :Itu mungkin (tanpa plpython atau plv8) dalam SQL murni juga (tetapi membutuhkan 9.3+, tidak akan berfungsi dengan 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
Sunting :
Versi, yang menyetel beberapa kunci &nilai:
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$;
Edit 2 :seperti yang dicatat oleh @ErwinBrandstetter, fungsi-fungsi di atas berfungsi seperti yang disebut UPSERT
(memperbarui bidang jika ada, menyisipkan jika tidak ada). Berikut adalah variannya, yang hanya 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$;
Edit 3 :Ini adalah varian rekursif, yang dapat disetel (UPSERT
) nilai daun (dan menggunakan fungsi pertama dari jawaban ini), terletak di jalur kunci (di mana kunci hanya dapat merujuk ke objek dalam, array dalam tidak didukung):
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$;
Diperbarui:Menambahkan fungsi untuk mengganti kunci bidang json yang ada dengan kunci lain yang diberikan. Dapat berguna untuk memperbarui tipe data dalam migrasi atau skenario lain seperti perubahan struktur data.
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;
Perbarui :fungsi dipadatkan sekarang.