Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

ユーザー独自属性をどう作るかみたいな話

例えばお問い合わせフォームとかで、名前とメアドは必須とする。ただ、あるユーザーはドロップダウンで予算種別や流入経路を出したい、とあるユーザーはFAX番号も出したい、みたいなやつ。

スキーマレスのFirebaseの場合ユーザーごとにスキーマ作れば終わる(アプリ側は大変だけど)んだけど、RDBはそうもいかないよね。

今まで見たなかで大きく3パターンあるようなので、整理をする。

1. 属性ごとにテーブルが作成する

DrupalというCMSで見たパターン。 属性を追加することでconfigが更新され、configには追加したフィールドの格納場所がわかる。で、Field APIでカスタム属性をを全部引っ張ることができるようだ。

2. metaテーブルを作る

WordPressが得意としている実装。option_metaとかuser_metaとか。

field_namefield_valueを保存するテーブルを作って、キー/値ペアを作るやつです。カラムのスキーマはバイナリ以外は自動的に文字列になるので、そのあたりが微妙。重量みたいなカスタム属性があって、4.3kgである場合、本来はDecimal(10,1)とかなんだろうけど。型情報も保存して、toXXXいれるしか無いんかな?

この種の設計は、SQLアンチパターンとはされているけど、格納する→表示するだけなら、まぁそこまで。検索したいとなると、無理。格納表示ならJSONでよいだろって思い始めている。

SQLアンチパターン EAVと4つの解決策

EAVだと検索性が死ぬので、それらの対応策としては、親のテーブルにtype属性を作って、そのtype属性に応じたテーブルを作りJOINするパターンが有る。STIってやつですかね。単一テーブル継承。

マルチテナントのアプリケーションになっちゃうと、ユーザー単位でSTIが作られるので、テーブルの継承が出ずに、結局EAVにならざるをえない(型が決まらないので)。field_type field_name field_value validation みたいなテーブル作って、そこで頑張る感じかな。。。

3. JSONカラムを作って逃げる

WordPressのカスタムプラグインなんかで、どっかで見た実装。フィールド、ラベル、タイプ、バリデーションなどをJSONで用意して、動的にフォームを組み立てて、値も入れちゃうパターン。実装も単純。

まとめ

  • カラムで吸収:STIJSON
  • レコードで吸収: metaテーブル(EAV)
  • テーブルで吸収: Drupal

EAVになったらJSONで大差ないよ派なので、JSONでいいかなー。