🔠

Aはないよ!!JSONデータ型のABC

に公開

JSONにはいろんな種類がある

Railsのschemaファイルでカラムと型を確認していたところ、t.jsonb :hogeなる記述を発見!!
JSONにいろんなタイプがあることを知らなかったので、使い分けについてまとめてみました。

JSONデータ型とは

そもそもJSONデータ型とは、データベースでJSON(JavaScript Object Notation)形式のデータを扱うための特別なデータ型です。
JSON形式は、データをキーと値のペア(もしくは配列)として柔軟に表現できるフォーマットで、多くのアプリケーションで使われています。
このデータ型を使うと、データベースでJSONデータを効率よく保存し、操作することができます。

JSONデータ型には、jsonjsonbという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データを扱う上での注意点

  1. データベースエンコーディング

    • PostgreSQLのエンコーディングがUTF8以外の場合、JSONデータで非ASCII文字を扱う際に制限があります
  2. 数値の扱い

    • JSONB型では、IEEE 754形式の数値範囲外の値(例: NaN, Infinity)は許可されません
  3. スキーマの工夫

    • JSONの柔軟性を活かしつつ、予測可能な構造を保つことで、クエリの記述や管理が容易になります

推奨される使い方

  • JSONを保存するだけならjson型
  • 検索やデータ操作を行う場合はjsonb型
  • 柔軟性を活かしつつ効率化を図るには、インデックスの活用が鍵です🔑

JSON型とJSONB型を上手に使い分け、効率的なデータベース設計を目指しましょう!

Discussion