CodeGym /コース /SQL SELF /JSONオブジェクトの結合と変更:||演算子とjsonb_concat()関数

JSONオブジェクトの結合と変更:||演算子とjsonb_concat()関数

SQL SELF
レベル 34 , レッスン 0
使用可能

もしJSONBがデータを入れる魔法の宝箱だとしたら、||jsonb_concat()はその宝箱を合体させたり中身を変えたりするツールだよ。実際には、複数のJSONオブジェクトを合体させたり、片方のデータをもう片方に追加したり、配列を一つのリストにまとめたりしたい場面が出てくる。

例えば、こんな2つのJSONBオブジェクトがあるとする:

{"name": "Alice", "age": 25}

{"city": "Wonderland", "hobbies": ["reading", "chess"]}

こうしたい場合:

{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}

または、2つのJSONB配列を結合したいとき:

[1, 2, 3]

[4, 5, 6]

結果はこうなる:

[1, 2, 3, 4, 5, 6]

これ全部、||jsonb_concat()でできるよ。じゃあ、詳しく見ていこう。

JSONB結合用||演算子

||演算子は、PostgreSQLで2つのJSONBオブジェクトや配列を結合できる。シンプルで速くて使いやすい。基本ルールはこんな感じ:

  • 2つのJSONBオブジェクトを結合すると、両方のキーと値が入ったオブジェクトになる。
  • キーがかぶった場合は、右側の値が左側の値を上書きする。
  • JSONB配列同士なら、左と右の配列の要素が一つの配列にまとめられる。

例1:2つのJSONBオブジェクトの結合

SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"city": "Wonderland", "hobbies": ["reading", "chess"]}'::jsonb AS merged_object;

結果:

{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}

例2:キーがかぶったときの値の更新

SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"age": 30, "city": "Wonderland"}'::jsonb AS updated_object;

結果:

{"name": "Alice", "age": 30, "city": "Wonderland"}

ここで"age"キーの値は、右側のオブジェクトの値で上書きされてるのに注目。

例3:配列の結合

SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS merged_array;

結果:

[1, 2, 3, 4, 5, 6]

JSONB結合用jsonb_concat()関数

jsonb_concat()関数は||演算子とほぼ同じ動きをするけど、関数として使えるから、関数内やトリガー、動的クエリで使いたいときに便利。2つのJSONB型引数を受け取って、結合した結果を返すよ。

例:jsonb_concat()の使い方

SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combined;

結果:

{"a": 1, "b": 3, "c": 4}

オブジェクトと配列の結合:ポイントと注意点

キーがかぶるオブジェクトを結合するときは、右側のオブジェクトの値が優先されるってことを覚えておこう。

例えば:

SELECT '{"key1": "value1"}'::jsonb || '{"key1": "value2"}'::jsonb AS result;

結果:

{"key1": "value2"}

値の上書きを避けたいなら、別のキーに保存するか、配列など他の方法を使おう。

あと、配列は常に右側の配列の要素が左側に追加される。例えば:

SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS result;

結果:

["a", "b", "c", "d"]

配列の中にオブジェクトがあっても、順番はそのまま:

SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS result;

結果:

[{"id": 1}, {"id": 2}, {"id": 3}]

実践例

ユーザープロフィールの更新。 例えば、usersテーブルがあって、プロフィールがJSONBで保存されてるとする:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    profile JSONB
);

INSERT INTO users (profile) VALUES ('{"name": "Alice", "age": 25}');

今度は居住都市を追加したい:

UPDATE users 
SET profile = profile || '{"city": "Wonderland"}'
WHERE id = 1;

クエリ結果:

{"name": "Alice", "age": 25, "city": "Wonderland"}

注文データの結合。 例えば、ordersテーブルがあるとする:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    details JSONB
);

INSERT INTO orders (details) VALUES ('{"items": [{"product": "laptop", "quantity": 1}]}');

今度は注文にもう一つ商品を追加したい:

UPDATE orders
SET details = jsonb_set(
    details,
    '{items}',
    details->'items' || '[{"product": "mouse", "quantity": 2}]'::jsonb
)
WHERE id = 1;

クエリ結果:

{"items": [{"product": "laptop", "quantity": 1}, {"product": "mouse", "quantity": 2}]}

||jsonb_concat()の違い

機能的には||演算子もjsonb_concat()関数も同じ。シンプルなクエリなら||の方が書きやすい。関数として明示的に呼び出したい場合やトリガー内で使いたい場合はjsonb_concat()が便利。

よくあるミスとその防ぎ方

ミス例:型が違うものを結合しようとする。

SELECT '{"key": "value"}'::jsonb || '["value"]'::jsonb;

結果:

ERROR:  jsonbオブジェクトと配列は結合できません

左がオブジェクト、右が配列だとPostgreSQLはそのまま結合できない。同じ型同士(オブジェクト同士、配列同士)じゃないとダメ。

見落としがち:JSONBでインデックスを作ってない

JSONBフィールドの値でよく検索するのにインデックスがないと、クエリがめっちゃ遅くなる。これは典型的なエラーじゃないけど、パフォーマンスに大きく影響する。GINインデックスを使うのを忘れずに:

CREATE INDEX idx_profile_data ON employees USING gin(profile);
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION