PostgreSQL 11+
Nếu bạn đã ở PostgreSQL phiên bản 11 (vì mới JSONB
hỗ trợ chuyển đổi loại
) đặt cược tốt nhất của bạn có lẽ là một hàm tùy chỉnh được viết bằng Perl hoặc Python.
Vì tôi ủng hộ Python 3, đây là một ví dụ chức năng:
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
$$;
... sau đó có thể được sử dụng như sau:
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"}]';
Vì vậy, có, điều kiện được sao chép, nhưng chỉ để giới hạn số lượng hàng phải chạm vào ngay từ đầu.
Để thực sự hoạt động khi cài đặt PostgreSQL 11 đơn giản, bạn cần có phần mở rộng plpython3u
và jsonb_plpython3u
:
CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;
Logic Python được giải thích:
for e in path_to_array:
tmp = tmp[e]
... đưa chúng ta đến mảng các mục nhập mà chúng ta cần xem xét.
for item in tmp:
if (entry_filters is None or entry_filters.items() <= item.items()):
item.update(replacement)
... đối với mỗi mục trong mảng, chúng tôi kiểm tra xem tiêu chí bộ lọc có null
hay không (entry_filters is None
=khớp với bất kỳ mục nhập nào) hoặc mục nhập "chứa" ví dụ được cung cấp bao gồm các khóa và giá trị (entry_filters.items() <= item.items()
).
Nếu mục nhập khớp, hãy ghi đè / thêm nội dung bằng mục thay thế được cung cấp.
Tôi hy vọng điều đó sẽ đi đúng hướng mà bạn đang tìm kiếm.
Nhìn vào các khả năng hiện tại của PostgreSQL liên quan đến sửa đổi JSON, nó sẽ rất phức tạp (nếu không muốn nói là phức tạp) và cần rất nhiều chi phí để làm điều tương tự với SQL thuần túy.
PostgreSQL 9.6+
Trong trường hợp bạn chưa có sẵn phiên bản 11, hàm sau sẽ thực hiện tương tự với chi phí là tự xử lý các chuyển đổi kiểu nhưng giữ cho nó hoàn toàn tương thích với API, vì vậy khi bạn nâng cấp, điều duy nhất bạn phải làm là thay thế hàm (không cần thay đổi bất kỳ câu lệnh nào sử dụng hàm này):
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)
$$;