はじめに
昨日コーディングインタビューにて「migrationファイルにおける不整合データの対策について」を問われた際にパッと答えることができなかったので、ここで供養していく。
問題
以下のようなテーブル定義のmigrationファイルがあった際、どのようにして不整合データの対策をしていくかといった内容。(以下Ruby on Railsのmigrationを例に)
def up
create_table :follows do |t|
t.references :follow_to, foreign_key: { to_table: :users }
t.references :follow_by, foreign_key: { to_table: :users }
t.timestamps
end
end
よくあるsnsのユーザーフォローの機能のテーブルをイメージしていただきたい。
followsテーブルとusersテーブルは1:Nの関係になっている。
どんな不整合が起こりうるか
思いつくのは存在しないユーザーとの関連データ/欠損データ/重複データの3つ。
- 存在しないユーザーとの関連データ
- 外部キー(follow_to,follow_by)に出鱈目なユーザーのidを格納することで生じるデータ
- 欠損データ
- 外部キー(follow_to,follow_by)にnullが格納されることで、必要なリレーションが欠損したデータ
- 重複データ
- フォローしたユーザーとされたユーザーの組み合わせが同じなレコードを複数存在させたデータ
どうやって対策するのか
- 存在しないユーザーとの関連データ
- 上記migrationは既に対応済みではあるが、外部キー制約を付与することで存在するユーザーのみを格納するようにする(referenceやadd_foreign_key)
- 欠損データ
- NOT NULL制約をすることで、不完全なデータを作成しないようにする
- 重複データ
- follow_to,follow_byの組み合わせにindexを追加して、重複データが作成されないようにする
上記の対策を施したmigrationは以下のようになる。
def up
create_table :follows do |t|
t.references :follow_to, null: false, foreign_key: { to_table: :users }
t.references :follow_by, null: false, foreign_key: { to_table: :users }
t.timestamps
end
add_index :follows, %i[follow_to_id follow_by_id], unique: true
end