次の定義の表があります。
_create table json_test (
filter_data jsonb);
_
そして私はそれにこのような値を挿入します:
_'{"task_packets": [
{
"state": "PROCEEDING",
"task_id": 1001
},
{
"state": "REVERTING",
"task_id": 1002
}
]}'
_
このjsonb
列を次のように更新します。
_'{"task_packets": [
{
"state": "DONE",
"task_id": 1001
},
{
"state": "REVERTING",
"task_id": 1002
}
]}'
_
つまり、task_packetsの配列内の指定された_task_id
_で値の状態を変更したいです。 jsonb_set()
関数を_#-
_演算子と組み合わせて使用することをお勧めします(最初に配列から値を削除してから、更新された状態でそれに追加します)。
どうすればできますか?
私がコメントしたように、これはこのようなテーブルで正規化されたDBレイアウトでより効率的です
CREATE TABLE task_packets (
task_id int PRIMARY KEY
, state text NOT NULL
-- or: state_id int NOT NULL REFERENCES state(state_id) ...
);
特に、一意のtask_id
番号を強制するPK制約を設定できます。そして、あなたが望むUPDATE
は簡単です。
しかし質問に答える:
宛先SELECT
:
SELECT *
FROM json_test jt
, LATERAL (
SELECT jsonb_set(filter_data
, '{task_packets}'
, jsonb_agg(CASE WHEN elem->>'task_id' = '1001'
THEN jsonb_set(elem, '{state}', to_jsonb(text 'DONE'))
ELSE elem
END)) AS filter_data_new
FROM jsonb_array_elements(filter_data->'task_packets') elem
) tp
WHERE jt.filter_data @> '{"task_packets": [{"task_id": 1001}]}';
私はLATERAL
joinを提案します。特に、プレーンで誤ってひとまとめにされる可能性がある複数の一致する行の可能性を除外します参加する。
宛先UPDATE
:
UPDATE json_test
SET filter_data =
(
SELECT jsonb_set(filter_data
, '{task_packets}'
, jsonb_agg(CASE WHEN elem->>'task_id' = '1001'
THEN jsonb_set(elem, '{state}', to_jsonb(text 'DONE'))
ELSE elem
END))
FROM jsonb_array_elements(filter_data->'task_packets') elem
)
WHERE filter_data @> '{"task_packets": [{"task_id": 1001}]}';
同じことは、UPDATE
(またはSELECT
にも)のcorrelated subqueryを使用して実装できます。
大きなテーブルでこれを高速にするには、適切なindex、理想的にはjsonb_path_ops
インデックスが必要です。
これを試して
update
json_test
set
filter_data =
jsonb_set(
filter_data ,
array['task_packets', elem_index::text, 'state'],
'"DONE"'::jsonb,
true)
from (
select
pos- 1 as elem_index
id
from
json_test,
jsonb_array_elements(filter_data ) with ordinality arr(elem, pos)
where
elem->>'task_id' = '1001'
) sub
where sub.id=id
これは非常に役立ちましたが、配列内の複数のキーを一度に更新する必要があり、9.5以上の連結ショートカットを使用しました ||。
update public.contactsdb
set data = (select jsonb_set(data, '{Contacts}', jsonb_agg(
elem || '{"Summary": "A User", "Email":"[email protected]"}'))
from jsonb_array_elements(data->'Contacts') elem )
where id in (select id from contactsdb,
jsonb_array_elements(data->'Contacts') as elems where elems->'Summary' is not null)
ブロック内の書式設定で申し訳ありません。正しく理解できません。 modはそれを持っています