Aはないよ!!JSONデータ型のABC
JSONにはいろんな種類がある
Railsのschemaファイルでカラムと型を確認していたところ、t.jsonb :hoge
なる記述を発見!!
JSONにいろんなタイプがあることを知らなかったので、使い分けについてまとめてみました。
JSONデータ型とは
そもそもJSONデータ型とは、データベースでJSON(JavaScript Object Notation)形式のデータを扱うための特別なデータ型です。
JSON形式は、データをキーと値のペア(もしくは配列)として柔軟に表現できるフォーマットで、多くのアプリケーションで使われています。
このデータ型を使うと、データベースでJSONデータを効率よく保存し、操作することができます。
JSONデータ型には、json
型 と jsonb
型という2つのJSONデータ型があります。
JSON型とJSONB型の違い
特徴 | json型 | jsonb型 |
---|---|---|
保存方法 | 入力されたJSONをそのまま文字列として保存する | バイナリ形式に変換して保存する(正規化が行われる為、格納処理は普通のJSON型の比べて遅い) |
データの解析 | 読み出しや操作時に毎回再解析が必要 | 保存時に解析するため、操作が高速 |
インデックス対応 | 対応していない | インデックスをサポートしていて、検索が高速 |
空白・順序の保持 | 空白やキーの順序を保持する | 空白や順序を保持せず、効率化される |
重複キーの扱い | 重複するキーをすべて保持する | 最後に定義されたキーのみ保持する |
一般的には、検索や操作が頻繁にある場合は jsonb型
を使う方が望ましいです。
ただし、データの元の形式(順序や空白)を保持する必要がある特殊なケースでは json型
を使用します。
JSON型の使い方例
1. シンプルな値
SELECT '5'::json; -- 数値としてJSONに保存
SELECT '"text"'::json; -- 文字列としてJSONに保存
2. 配列
SELECT '[1, 2, "foo", null]'::json; -- 数値や文字列、nullを含む配列
3. オブジェクト
SELECT '{"key": "value", "number": 10}'::json; -- キーと値のペア
SELECT '{"user": {"name": "Fumi", "age": 20}, "active": true}'::json; -- 入れ子もOK
JSONB型におけるインデックスの活用
jsonb
型の最大の利点は、インデックスを活用できる点です。
多くのJSONデータが格納されている場合、以下のように検索を高速化できます。
GINインデックスを利用した検索
CREATE INDEX idxgin ON api USING gin (jdoc);
# JSONオブジェクトの中から特定のキーと値のペアを検索する
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';
RailsでJSONBを管理する方法
1. モデルとマイグレーションの作成
Rails 4.2以降、PostgreSQLのJSONB型を標準でサポートしています。
以下のコマンドで、モデルとJSONB型のカラムを作成します。
bin/rails generate model Patient details:jsonb
マイグレーションファイル例:
def change
create_table :patients do |t|
t.jsonb :details # 患者情報を保存するJSONBカラム
t.timestamps null: false
end
add_index :patients, :details, using: 'gin'
end
2. データの作成
データをハッシュ形式 または JSON形式の文字列 で保存できます。
例1: ハッシュ形式でデータを保存する
Patient.create(details: { name: "田中太郎", age: 45, diagnosis: "高血圧", doctor: "佐藤医師", hospital: "東京中央病院" })
例2: JSON文字列でデータを保存する
Patient.create(details: '{"name": "鈴木花子", "age": 30, "diagnosis": "花粉症", "doctor": "山本医師", "hospital": "大阪総合病院"}')
3. データの検索
PostgreSQLのJSONB演算子を活用して、データを検索します。
参考:JSON関数と演算子
例1: 特定の診断名で患者を検索する
Patient.where("details->>'diagnosis' = ?", "高血圧")
例2: 特定の病院に通う患者を検索
Patient.where("details->>'hospital' = ?", "東京中央病院")
例3: JSONBキーの存在確認
?
演算子を使って特定のキーが存在するか確認できます。
Patient.where("details ? 'doctor'")
4. 具体的なデータ作成と検索の例
データを登録する
Patient.create(details: { name: "伊藤一郎", age: 60, diagnosis: "糖尿病", doctor: "中村医師", hospital: "名古屋市立病院" })
特定の医師が担当している患者を検索する
Patient.where("details->>'doctor' = ?", "中村医師")
患者データを更新する
patient = Patient.find_by("details->>'name' = ?", "田中太郎")
patient.details["diagnosis"] = "糖尿病"
patient.save
JSONデータを扱う上での注意点
-
データベースエンコーディング
- PostgreSQLのエンコーディングがUTF8以外の場合、JSONデータで非ASCII文字を扱う際に制限があります
-
数値の扱い
- JSONB型では、IEEE 754形式の数値範囲外の値(例: NaN, Infinity)は許可されません
-
スキーマの工夫
- JSONの柔軟性を活かしつつ、予測可能な構造を保つことで、クエリの記述や管理が容易になります
推奨される使い方
-
JSONを保存するだけなら
json型
-
検索やデータ操作を行う場合は
jsonb型
- 柔軟性を活かしつつ効率化を図るには、インデックスの活用が鍵です🔑
JSON型とJSONB型を上手に使い分け、効率的なデータベース設計を目指しましょう!
Discussion