独学者Fossa

独学していることなど

Fossa Advent Calendar 12日目

アドベントカレンダー
アドベントカレンダー

JSON

私自身の勉強のために、書いているので、間違ったことを書いているかもしれません。

最近、便利だなと思ったのは、データベースにおけるJSONフィールド(カラム)です。

SQLで、基本的には、きちんとカラムを定義するべきだと思います。

下記のように、保存したいデータがあったとします。

  {
    "name": "Google",
    "url": "https://www.google.co.jp",
    "login_id": "example",
    "password": "password"
  }

サイトにログインする時に、必要な情報として保存したい場合を想定しています。

ところが、サイトによって、本人確認のために、もう一つ情報を質問してくる場合があります。

例えば、現在、住んでいる所と出身地が異なる人は、出身地がどこか答えることでログインできるとします。*1

中には、質問自体を、いくつかの中から選んだり、ご自身で質問事項を作成できるサイトもあります。*2

question: 出身地
answer: 東京都

というカラムを作ればいいのですが、全てのサイトが同じように、必要になるわけでは、ありません。

もちろん、必要なサイトのみ情報を保存して、情報が存在しなかったとしても、カラム自体は存在させておけばいいという考え方もあります。

しかし、必要としないカラムが沢山あった場合、困ります。*3

そこで、JSONフィールド(カラム)の登場です。

  {
    "name": "Hoge",
    "url": "https://example.com",
    "json": {
      "login_id": "xxxxxxxxx",
      "password": "password",
      "login_id2": "zzzzzzzz",
      "password2": "password2",
      "question": "出身地",
      "answer": "東京都"
    }
  }

上記の場合は、サイトによってlogin_idが2つ存在した場合でも、対応できるという例です。*4
わざわざ、一つのサイトのために、login_id2というカラムを用意しなくて、すみます。

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

<省略>

    /**
     * 利用するデータベース名.
     *
     * @var string
     */
    protected $dbName = 'sqlite';

    /**
     * 作成するテーブル名.
     *
     * @var string
     */
    protected $tableName = 'sites';

<省略>

    Schema::connection($this->dbName)->create($this->tableName, function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('url')->nullable();
        $table->json('json');
    });

login_idの一覧が必要になった場合は、下記の通り。

<?php

<省略>

    $loginId = Site::all()->pluck('json.login_id');

忘れないように保存しておくだけなど、特定の使い方しか想定しておりません。

*1:例えが悪かったかな?

*2:忘れたけど、ゆうちょ銀行だったかな?

*3:正規化する場合もあるけど

*4:他に良い例えが思い浮かばなかった