かしいのはてな

技術ブログ備忘録用

jsonbの部分更新

jsonスキーマはpostgreSQL9.2 から取り扱えるようになり多様なデータ構造を持つことが出来るようになりました。key value のセットでデータ保存しますが

 

# select version();
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 9.6.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-17), 64-bit
(1 row)

 

データの部分更新をしたいときですが、value がstring かnumber で更新方法が違いました。例えばこうゆうデータがあって

 

# select id, json_contents from notifications limit 1;
-[ RECORD 1 ]-+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | 1
json_contents | {"offer_id": 4333}

-[ RECORD 2 ]-+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | 2
json_contents | {"offer_id": "4333"}

 

number と string で定義されたoffer_id があります。この場合だと

select * from notifications where json_contents = jsonb_set(json_contents, '{"offer_id"}', '4333');

で、1件しかとれません。(id:1 のほう)

なので、整合性のため、データを揃えます。

update
  notifications
set
 json_contents = '{}'::jsonb || json_contents || json_build_object('offer_id',(json_contents->>'offer_id')::integer)::jsonb
;

update table_name set col = default || 'hohfeofe' の発想です。

一旦空のデータを作ってから、元コンテンツをmergeして、offer_id に対して、元データをstring -> integer -> jsonb にキャストしてます。

 

この場合だと、jsonのvalue string -> integer , integer -> string でもいけると思います。