DBスキーマを設計しよう
このページで学ぶこと
- リレーショナルデータベースの基本がわかる
- ER図(エンティティ関係図)を書ける
- アプリのデータ構造をテーブルとして表現できる
データベースとは
データベース(DB) はデータを永続的に保存する仕組みです。
アプリを再起動してもデータが消えないのはDBがあるからです。
リレーショナルデータベース
とんペディアで使用している Supabase(PostgreSQL)はリレーショナルデータベースです。
データはExcelのような「テーブル(表)」の形で保存されます。
usersテーブル:
| id | name | email |
|----|--------|-------------------|
| 1 | 田中太郎 | tanaka@example.com |
| 2 | 鈴木花子 | suzuki@example.com |
todosテーブル:
| id | title | completed | user_id |
|----|----------|-----------|---------|
| 1 | 牛乳を買う | false | 1 |
| 2 | 洗濯する | true | 1 |
| 3 | 読書する | false | 2 |todos テーブルの user_id 列 (今後、これを todos.user_id のように表現します) が users.id と紐づいています。
これを外部キーといいます。
外部キーを使わず todos テーブルにユーザー情報(id, 名前, メールアドレス)を直接挿入した場合、例えば田中太郎さんのメールアドレスが変わった時に users テーブルの email カラムだけでなく、todos テーブルの田中太郎さんの行もすべて更新する必要が出てきます。
外部キーを使って todos テーブルにユーザーID (不変かつユーザーを一意に識別できる情報) だけ入れておけば、ユーザーのメールアドレスが変わっても users テーブルの email カラムだけ更新すればOKです。
ER図(エンティティ関係図)
テーブルの構造と関係を図で表したものを ER図(Entity Relationship Diagram) といいます。
設計の段階でER図を書くことで、データの整合性を考えながら設計できます。
関係(リレーション)の種類
||--||: 1対1(1つのユーザーが1つのプロフィールを持つ)||--o{: 1対多(1つのユーザーが複数のTodoを持つ)}o--o{: 多対多(複数のタグが複数の記事につく)
データ型とキーの見方
| データ型 | 意味 | 使う例 |
|---|---|---|
int | 整数を入れる型 | id, post_id |
string | 文字列を入れる型 | name, email, title |
boolean | true / false を入れる型 | completed |
datetime | 日時を入れる型 | created_at |
やってみよう:ミニブログのスキーマを設計する
ミニブログアプリ(ユーザーが投稿を書き、コメントできる)のスキーマを考えてみましょう。
ステップ1: 必要なデータを洗い出す
まず「このアプリで何を保存する必要があるか」を書き出します。
- ユーザー: 名前、メールアドレス、パスワード
- 投稿: タイトル、本文、誰が書いたか、いつ書いたか
- コメント: 内容、どの投稿へのコメントか、誰が書いたか
ステップ2: テーブルに整理する
ステップ3: 設計の考え方のポイント
主キー(PK)
- 各行を一意に識別するためのカラム
- 同じ値が重ならないようにする
外部キー(FK)
- 他のテーブルの主キーを参照するカラム
- テーブル同士をつなぐための値
- たとえば
posts.author_idはusers.idを参照する
created_at
- 作成日時はほぼ全テーブルに入れておくと便利
パスワードの保存
- パスワードは平文(そのままの文字列)で保存してはいけない
- 今回は Supabase Auth を使うので、パスワードは Supabase が管理してくれる
usersテーブルにはemailとnameだけ持てばOK
Prisma スキーマへの変換
ER図を書いたら、次は Prisma スキーマに落とし込みます。
ここでは Todo アプリの users / todos テーブルを例にします。
(Prismaの詳細は次のページで学びます)
// prisma/schema.prisma のイメージ
model User {
id Int @id @default(autoincrement())
name String
email String @unique
todos Todo[] // 1対多のリレーション(Userは複数のTodoを持てる)
createdAt DateTime @default(now())
}
model Todo {
id Int @id @default(autoincrement())
title String
completed Boolean @default(false)
userId Int @map("user_id")
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
@@map("todos")
}確認しよう
- テーブル・カラム・外部キーの意味が説明できる
- 自分のアプリに必要なデータを洗い出せた
- ER図(Mermaidでも手書きでも)を書けた
- 1対多の関係を設計できた
AIに聞いてみよう
「多対多のリレーションを設計するにはどうすれば良いですか?」