JSONBって、ネストされたオブジェクトや配列みたいな複雑なデータ構造を保存できる超便利なツールなんだ。でも、保存するだけじゃ意味ないよね。やっぱりデータを取り出せなきゃ。例えば、usersテーブルのdataカラムに、ユーザーの設定が全部JSONBで入ってるとする。ユーザーがどんなテーマを選んでるか知りたい?それならJSONBオブジェクトから取り出す必要があるよ。
もしJSONBが宝箱なら、->、->>、#>>みたいなオペレーターやjsonb_extract_path()みたいな関数はカギみたいなもん。どうやって使うか見ていこう!
JSONBを扱う基本のオペレーター
PostgreSQLにはJSONBを扱うための主要なオペレーターがいくつか用意されてる。これらを使えば、キーやネストされたオブジェクト、配列から値を取り出せるよ。主なものはこんな感じ:
オペレーター ->
->オペレーターは、指定したキーのオブジェクトや配列を取り出すよ。JSONと同じフォーマットで値が欲しいときはこれを使おう。
例:
-- データ例
SELECT '{"name": "Alice", "age": 25}'::jsonb -> 'name';
-- 結果: "Alice"
オペレーター ->>
->>オペレーターは->に似てるけど、取り出した値をテキストとして返すよ。データをシンプルなテキストで欲しいときに便利!
例:
-- データ例
SELECT '{"name": "Alice", "age": 25}'::jsonb ->> 'age';
-- 結果: "25"(文字列)
オペレーター #>>
#>>オペレーターは、指定したパスでネストされたオブジェクトからデータを取り出すよ。パスはキーの配列で渡す。
例:
-- データ例
SELECT '{"user": {"name": "Bob", "details": {"age": 30}}}'::jsonb #>> '{user, details, age}';
-- 結果: "30"(文字列)
->と->>の違い:
データ型(例えば配列やオブジェクト)をそのまま保持したいなら->を使おう。テキストが欲しいなら->>だね。
JSONBを扱う関数の使い方
jsonb_extract_path()関数は、指定したパスでJSONBオブジェクトから値を取り出すよ。これは#>>オペレーターの関数バージョンみたいなもんだけど、ちょっと表現力が高い。
例:
SELECT jsonb_extract_path('{"user": {"name": "Alice", "settings": {"theme": "dark"}}}'::jsonb, 'user', 'settings', 'theme');
-- 結果: "dark"
もし最初からテキスト値が欲しいなら、jsonb_extract_path_text()を使おう。これはjsonb_extract_path()と同じだけど、返り値が文字列になる。
例:
SELECT jsonb_extract_path_text('{"user": {"name": "Alice", "settings": {"theme": "dark"}}}'::jsonb, 'user', 'settings', 'theme');
-- 結果: dark
実践サンプル
キーで値を取り出す。 例えば、productsテーブルがあって、detailsカラムにJSONBデータが入ってるとしよう:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
details JSONB
);
INSERT INTO products (name, details) VALUES
('Laptop', '{"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "Intel i7"}}'),
('Phone', '{"brand": "Apple", "price": 1000, "specs": {"ram": "4GB", "cpu": "A13"}}');
結果:
| id | name | details |
|---|---|---|
| 1 | Laptop | {"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "Intel i7"}} |
| 2 | Phone | {"brand": "Apple", "price": 1000, "specs": {"ram": "4GB", "cpu": "A13"}} |
全商品のブランドを取り出す。
SELECT name, details->'brand' AS brand FROM products;
結果:
| name | brand |
|---|---|
| Laptop | "Dell" |
| Phone | "Apple" |
テキスト値を取り出す。 ブランド名をクォートなしで欲しいなら、->>オペレーターを使おう:
SELECT name, details->>'brand' AS brand FROM products;
結果:
| name | brand |
|---|---|
| Laptop | Dell |
| Phone | Apple |
ネストされたデータを取り出す。 各商品のメモリ容量(ram)を取り出してみよう:
SELECT name, details#>>'{specs, ram}' AS ram FROM products;
結果:
| name | ram |
|---|---|
| Laptop | 16GB |
| Phone | 4GB |
パスでデータを取り出す。 同じことをjsonb_extract_path_text()関数でもできるよ:
SELECT name, jsonb_extract_path_text(details, 'specs', 'ram') AS ram FROM products;
結果:
| name | ram |
|---|---|
| Laptop | 16GB |
| Phone | 4GB |
よくあるミスとその回避法
こんなときによくミスしがち:
- 間違ったパスでデータを取り出そうとする。例えば、キーが存在しない場合は
nullになるよ。 - 目的に合わないオペレーターを使う。
->はオブジェクトや配列用、テキストが欲しいなら->>を使おう。
ミスの例:
-- ミス: 'nonexistent'キーは存在しない
SELECT details->>'nonexistent' FROM products;
-- 結果: null
アドバイス:クエリを書く前に、必ずデータ構造をチェックしよう。ミスを防げるよ!
実際のアプリでの使い道
JSONBからデータを取り出すのは、いろんなアプリで使われてるよ:
- e-commerceで商品のスペックを扱うとき。
- Webアプリでユーザー設定を保存するとき。
- 分析でイベントやログみたいな構造化データを処理するとき。
もう一つ例を見てみよう。ordersテーブルに注文データが入ってるとする:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_name TEXT,
items JSONB
);
INSERT INTO orders (customer_name, items) VALUES
('John', '[{"product": "Laptop", "quantity": 1}, {"product": "Mouse", "quantity": 2}]'),
('Alice', '[{"product": "Phone", "quantity": 1}]');
注文から全商品の名前を取り出してみよう:
SELECT customer_name, jsonb_array_elements(items)->>'product' AS product FROM orders;
結果:
| customer_name | product |
|---|---|
| John | Laptop |
| John | Mouse |
| Alice | Phone |
このあと、さらにJSONBのネストされたデータや、分析しやすい形への変換も深掘りしていくよ。もっと面白い発見が待ってるから、楽しみにしてて!
GO TO FULL VERSION