Pembaruan : Dengan PostgreSQL 9.5 , ada beberapa jsonb
fungsi manipulasi di dalam PostgreSQL itu sendiri (tetapi tidak ada untuk json
; pemeran diperlukan untuk memanipulasi json
nilai).
Menggabungkan 2 (atau lebih) objek JSON (atau array gabungan):
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, pengaturan kunci sederhana dapat dilakukan dengan menggunakan:
SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')
Di mana <key>
harus string, dan <value>
bisa apa pun jenis to_jsonb()
menerima.
Untuk mengatur nilai jauh di dalam hirarki JSON , jsonb_set()
fungsi tersebut 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
juga bisa memuat indeks array JSON & bilangan bulat negatif yang muncul di sana terhitung 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 array JSON (sambil mempertahankan semua nilai asli) , jsonb_insert()
fungsi tersebut dapat digunakan ( dalam 9.6+; fungsi ini saja, 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 dalam path
hitungan dari akhir array JSON.
Jadi, selanjutnya 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
in target
adalah kunci objek JSON. Dalam hal ini, itu hanya akan menambahkan pasangan nilai kunci baru untuk objek JSON ketika 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 ke dalam objek json secara langsung json_object_agg()
.
Jawaban asli : Dimungkinkan (tanpa plpython atau plv8) dalam SQL murni juga (tetapi perlu 9.3+, tidak akan bekerja 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
Edit :
Versi, yang menetapkan 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$;
Sunting 2 : seperti @ErwinBrandstetter mencatat fungsi-fungsi di atas berfungsi seperti yang disebut UPSERT
(memperbarui bidang jika ada, menyisipkan jika tidak ada). Berikut ini varian, 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$;
Sunting 3 : Berikut adalah varian rekursif, yang dapat mengatur ( UPSERT
) nilai daun (dan menggunakan fungsi pertama dari jawaban ini), yang terletak di jalur-kunci (di mana kunci hanya bisa 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$;
Perbarui : fungsi dipadatkan sekarang.
select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two');
pesan kesalahan adalahERROR: could not determine polymorphic type because input has type "unknown"