PostgreSQL 11+
Jika Anda sudah menggunakan PostgreSQL v. 11 (karena JSONB
baru jenis dukungan konversi
) taruhan terbaik Anda mungkin adalah fungsi khusus yang ditulis dalam Perl atau Python.
Karena saya menyukai Python 3, berikut adalah contoh fungsionalnya:
CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
RETURNS jsonb
TRANSFORM FOR TYPE jsonb
LANGUAGE plpython3u
AS $$
v_new = val
tmp = v_new
for e in path_to_array:
tmp = tmp[e]
for item in tmp:
if (entry_filters is None or entry_filters.items() <= item.items()):
item.update(replacement)
return v_new
$$;
...yang kemudian dapat digunakan sebagai berikut:
UPDATE configuration
SET
config = jsonb_replace_in_array(
config,
'{data}',
'{"value":"changed"}'::jsonb,
'{"oid":"11.5.15.1.4","instance":"1.1.4"}'::jsonb
)
WHERE config->'data' @> '[{"oid":"11.5.15.1.4","instance":"1.1.4"}]';
Jadi ya, kondisinya diduplikasi, tetapi hanya untuk membatasi jumlah baris yang harus disentuh di tempat pertama.
Untuk benar-benar bekerja pada instalasi PostgreSQL 11 biasa, Anda memerlukan ekstensi plpython3u
dan jsonb_plpython3u
:
CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;
Logika Python menjelaskan:
for e in path_to_array:
tmp = tmp[e]
...membawa kita ke array entri yang perlu kita lihat.
for item in tmp:
if (entry_filters is None or entry_filters.items() <= item.items()):
item.update(replacement)
...untuk setiap item dalam larik, kami memeriksa apakah kriteria filter adalah null
(entry_filters is None
=cocok dengan entri mana pun) atau apakah entri "berisi" contoh yang diberikan termasuk kunci dan nilai (entry_filters.items() <= item.items()
).
Jika entri cocok, maka timpa/tambahkan konten dengan pengganti yang disediakan.
Saya harap itu menuju ke arah yang Anda cari.
Melihat kemampuan PostgreSQL saat ini terkait dengan modifikasi JSON, itu akan menjadi sangat kompleks (jika tidak rumit) dan memperkenalkan banyak overhead untuk melakukan hal yang sama dengan SQL murni.
PostgreSQL 9.6+
Jika Anda belum memiliki versi 11 yang tersedia, fungsi berikut akan melakukan hal yang sama dengan mengorbankan penanganan konversi jenis dengan sendirinya tetapi tetap sepenuhnya kompatibel dengan API, jadi Anda setelah Anda memutakhirkan, satu-satunya hal yang harus Anda lakukan adalah mengganti fungsi (tidak ada perubahan pada pernyataan apa pun yang menggunakan fungsi ini diperlukan):
CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
RETURNS jsonb
LANGUAGE plpython3u
AS $$
import json
v_new = json.loads(val)
t_replace = json.loads(replacement)
t_filters = json.loads(entry_filters)
tmp = v_new
for e in path_to_array:
tmp = tmp[e]
for item in tmp:
if (entry_filters is None or t_filters.items() <= item.items()):
item.update(t_replace)
return json.dumps(v_new)
$$;