【データ構造】users・teams・members・tasksのつながりを理解する
このページでやること
このページでは、Firestoreに保存するデータの形を整理します。
Firestoreとは、Firebaseのデータベースです。
データベースとは、アプリの情報を保存する場所です。
今回のアプリでは、主に次の4つを使います。
| データ名 | 一言説明 |
|---|---|
users | アプリを使う人のプロフィール |
teams | タスクを共有するチーム |
members | チームに参加している人 |
tasks | チーム内で管理する作業 |
このページではコードをたくさん書きません。
次のチーム作成に進む前に、「どこに何を保存するのか」を確認します。
今日のゴール
今日のゴールは、次の形を理解することです。
users
└ uid
teams
└ teamId
├ members
│ └ uid
└ tasks
└ taskId
最初は難しく見えるかもしれません。
でも、短く言うとこうです。
users
↓
ユーザー情報
teams
↓
チーム情報
teamsの中のmembers
↓
そのチームに参加している人
teamsの中のtasks
↓
そのチームのタスク
npmや環境変数はこのページで必要?
このページでは、npmは使いません。
環境変数も設定しません。
環境変数とは、パソコン全体で使う設定値のことです。
このページでやることは、Firestoreのデータ構造を理解することです。
Firestoreの保存場所を見る
↓
users・teams・members・tasksの役割を知る
↓
次のチーム作成に備える
まずFirestoreの基本を確認する
Firestoreでは、データを次の形で保存します。
コレクション
└ ドキュメント
└ フィールド
それぞれ一言で説明します。
| 単語 | 一言説明 |
|---|---|
| コレクション | 同じ種類のデータをまとめる箱 |
| ドキュメント | 1件分のデータ |
| フィールド | ドキュメントの中に入る項目 |
| サブコレクション | ドキュメントの中に作る小さなコレクション |
たとえば、ユーザー情報ならこうです。
users
└ abc123
├ displayName
├ email
└ department
この場合、
users
がコレクションです。
abc123
がドキュメントです。
displayName
email
department
がフィールドです。
今回の全体構造
今回のアプリでは、Firestoreを次の形で使います。
users
└ uid
teams
└ teamId
├ members
│ └ uid
└ tasks
└ taskId
これを日本語で書くと、こうです。
ユーザー一覧
└ ユーザー1人分
チーム一覧
└ チーム1つ分
├ メンバー一覧
│ └ メンバー1人分
└ タスク一覧
└ タスク1件分
つまり、チームの中に、そのチームのメンバーとタスクを入れます。
usersとは何か
users は、アプリを使うユーザーのプロフィールを保存する場所です。
プロフィールとは、名前や所属など、その人に関する情報のことです。
保存場所は次の形です。
users/{uid}
uid とは、Firebase Authenticationがユーザーごとに発行するIDです。
たとえば、山田太郎さんの uid が abc123 なら、保存場所はこうなります。
users/abc123
中身は、たとえば次のようになります。
users/abc123
displayName: 山田太郎
email: yamada@example.com
department: 開発チーム
photoUrl:
defaultRole: member
createdAt: 作成日時
updatedAt: 更新日時
usersに保存する項目
users/{uid} に保存する主な項目は、次の通りです。
| 項目 | 一言説明 |
|---|---|
displayName | 画面に表示する名前 |
email | ログインやメンバー検索に使うメール |
department | 所属・部署・学校名など |
photoUrl | プロフィール画像のURL。今回は空文字 |
defaultRole | 初期の役割。今回は member |
createdAt | 作成日時 |
updatedAt | 更新日時 |
URLとは、画像やページなどの場所を表す文字列です。
今回は画像機能を作らないので、photoUrl は空のままで進めます。
teamsとは何か
teams は、タスクを共有するチームを保存する場所です。
チームとは、同じタスクを一緒に管理するグループのことです。
保存場所は次の形です。
teams/{teamId}
teamId とは、チームごとに作られるIDです。
たとえば、開発チームを作ると、Firestore上では次のようになります。
teams/team001
中身は、たとえば次のようになります。
teams/team001
name: 開発チーム
ownerId: abc123
memberIds: [abc123]
createdAt: 作成日時
updatedAt: 更新日時
teamsに保存する項目
teams/{teamId} に保存する主な項目は、次の通りです。
| 項目 | 一言説明 |
|---|---|
name | チーム名 |
ownerId | チームを作った人のuid |
memberIds | 参加メンバーのuid一覧 |
createdAt | 作成日時 |
updatedAt | 更新日時 |
memberIds は、とても大切です。
これは、そのチームに参加しているユーザーの uid を配列で保存します。
配列とは、複数の値をまとめたリストのことです。
memberIds: [abc123, xyz789]
このように保存しておくと、「自分が参加しているチームだけ」を取り出しやすくなります。
なぜmemberIdsが必要なのか
トーク一覧画面では、自分が参加しているチームだけを表示したいです。
たとえば、山田さんの uid が abc123 だったとします。
その場合、Firestoreから次のように探します。
memberIdsにabc123が含まれるチームだけ表示する
Flutterでは、あとで次のような検索を使います。
.where('memberIds', arrayContains: uid)
arrayContains は、配列の中に指定した値が含まれているか調べるFirestoreの検索条件です。
これによって、ログイン中のユーザーが参加しているチームだけを表示できます。
membersとは何か
members は、あるチームに参加しているメンバーを保存する場所です。
メンバーとは、チームに参加しているユーザーのことです。
保存場所は次の形です。
teams/{teamId}/members/{uid}
たとえば、開発チーム team001 に、山田さん abc123 が参加している場合はこうなります。
teams/team001/members/abc123
中身は、たとえば次のようになります。
teams/team001/members/abc123
uid: abc123
email: yamada@example.com
displayName: 山田太郎
role: owner
joinedAt: 参加日時
membersに保存する項目
teams/{teamId}/members/{uid} に保存する主な項目は、次の通りです。
| 項目 | 一言説明 |
|---|---|
uid | メンバーのユーザーID |
email | メンバーのメールアドレス |
displayName | メンバーの表示名 |
role | チーム内での権限 |
joinedAt | チームに参加した日時 |
role とは、その人が何をできるかを表す権限です。
権限とは、操作できる範囲を決めるルールです。
今回のアプリでは、次の4つを使います。
| 権限 | 一言説明 |
|---|---|
owner | チームの所有者。すべて操作できる |
admin | 管理者。メンバー追加やタスク削除ができる |
member | 一般メンバー。タスク作成や編集ができる |
viewer | 閲覧のみ |
なぜmembersとmemberIdsの両方が必要なのか
ここは少し大切です。
今回のアプリでは、teams の中に memberIds を保存します。
さらに、teams/{teamId}/members/{uid} にもメンバー情報を保存します。
「同じような情報を2か所に持つの?」と思うかもしれません。
理由は、役割が違うからです。
| データ | 役割 |
|---|---|
memberIds | 自分が参加しているチームを探すため |
members | メンバーの名前・メール・権限を管理するため |
memberIds は検索用です。
members は管理用です。
このように、Firestoreでは検索しやすくするために、必要な情報を少し重複して持つことがあります。
重複とは、同じ情報を複数の場所に持つことです。
tasksとは何か
tasks は、チーム内のタスクを保存する場所です。
タスクとは、やるべき作業のことです。
保存場所は次の形です。
teams/{teamId}/tasks/{taskId}
たとえば、開発チーム team001 に「ログイン画面を作る」というタスクを作ると、こうなります。
teams/team001/tasks/task001
中身は、たとえば次のようになります。
teams/team001/tasks/task001
title: ログイン画面を作る
description: メールとパスワードの入力欄を作る
status: todo
priority: high
assigneeEmail: yamada@example.com
assigneeId: abc123
createdBy: abc123
createdAt: 作成日時
updatedAt: 更新日時
tasksに保存する項目
teams/{teamId}/tasks/{taskId} に保存する主な項目は、次の通りです。
| 項目 | 一言説明 |
|---|---|
title | タスク名 |
description | タスクの説明 |
status | 進行状況 |
priority | 優先度 |
assigneeEmail | 担当者メール |
assigneeId | 担当者のuid |
createdBy | 作成者のuid |
createdAt | 作成日時 |
updatedAt | 更新日時 |
status は、タスクの進行状況です。
今回のアプリでは、次の3つを使います。
| status | 表示名 |
|---|---|
todo | 未対応 |
doing | 進行中 |
done | 完了 |
priority は、優先度です。
優先度とは、どのタスクを先に対応するべきかを表すものです。
なぜtasksをteamsの中に入れるのか
タスクは、チームごとに分けたいです。
たとえば、開発チームと営業チームがあるとします。
開発チームのタスク
├ ログイン画面を作る
└ Firestore接続を確認する
営業チームのタスク
├ 見積書を送る
└ 打ち合わせ日程を確認する
これが混ざると困ります。
そこで、タスクはチームの中に保存します。
teams/{teamId}/tasks/{taskId}
こうすると、チームを開いたときに、そのチームのタスクだけを表示できます。
4つのデータのつながり
ここまでの内容を、もう一度つなげて見ます。
users/{uid}
↓
ユーザーのプロフィール
teams/{teamId}
↓
チームの基本情報
teams/{teamId}/members/{uid}
↓
そのチームに参加している人と権限
teams/{teamId}/tasks/{taskId}
↓
そのチームのタスク
実際のアプリの流れにすると、こうです。
ユーザーが新規登録する
↓
users/{uid} にプロフィール保存
ユーザーがチームを作る
↓
teams/{teamId} を作成
↓
teams/{teamId}/members/{uid} にownerとして保存
↓
teams/{teamId}.memberIds にuidを入れる
チームを開く
↓
teams/{teamId}/tasks からタスクを取得する
メンバーを追加する
↓
usersからメールで検索
↓
teams/{teamId}/members/{uid} に追加
↓
teams/{teamId}.memberIds にuidを追加
画面とデータの対応
画面ごとに使うデータを整理します。
| 画面 | 使うデータ |
|---|---|
| 新規登録画面 | users/{uid} |
| トーク一覧画面 | teams |
| チーム作成画面 | teams/{teamId}、members/{uid} |
| タスク一覧画面 | teams/{teamId}/tasks |
| タスク作成画面 | teams/{teamId}/tasks/{taskId} |
| メンバー管理画面 | teams/{teamId}/members、users |
| メンバー追加画面 | users、members、memberIds |
「どの画面が、どのデータを使っているか」を見ておくと、コードが読みやすくなります。
Firestore Consoleで見る場所
Firebase Consoleでは、次の順番で確認できます。
Firebase Console
↓
Firestore Database
↓
データ
そこで、次のような構造を確認します。
users
teams
teams の中の1つのチームを開くと、サブコレクションとして次が見えます。
members
tasks
サブコレクションとは、ドキュメントの中に作るコレクションのことです。
次のページで使うチーム作成の考え方
次のページでは、チーム作成を作ります。
チームを作るときは、1つのデータだけではなく、2つの場所に保存します。
teams/{teamId}
teams/{teamId}/members/{uid}
さらに、teams/{teamId} の中に memberIds も入れます。
memberIds: [ログイン中ユーザーのuid]
つまり、チーム作成では、次の3つを同時に作ります。
1. チーム情報を作る
2. 作成者をメンバーとして登録する
3. 作成者のuidをmemberIdsに入れる
これが分かっていれば、次のチーム作成コードがかなり読みやすくなります。
まず覚える形
このページで全部を暗記する必要はありません。
まずは、これだけ覚えてください。
users/{uid}
↓
ユーザー情報
teams/{teamId}
↓
チーム情報
teams/{teamId}/members/{uid}
↓
チームのメンバー情報
teams/{teamId}/tasks/{taskId}
↓
チームのタスク情報
この4つが今回のアプリの土台です。
よくある混乱ポイント
| 混乱すること | 考え方 |
|---|---|
users と members の違い | users は全体のユーザー情報、members はチーム内の参加情報 |
uid と teamId の違い | uid はユーザーID、teamId はチームID |
なぜ memberIds が必要か | 自分の参加チームを検索しやすくするため |
なぜ tasks を teams の中に入れるか | チームごとにタスクを分けるため |
| なぜ同じメールを複数場所に持つか | 画面表示や検索を簡単にするため |
ミニ確認問題
Q1. users/{uid} には何を保存しますか?
回答
ユーザーのプロフィールを保存します。
たとえば、名前、メールアドレス、所属、作成日時などです。
Q2. teams/{teamId} には何を保存しますか?
回答
チームの基本情報を保存します。
たとえば、チーム名、作成者のuid、参加メンバーのuid一覧、作成日時などです。
Q3. teams/{teamId}/members/{uid} には何を保存しますか?
回答
そのチームに参加しているメンバー情報を保存します。
たとえば、uid、メールアドレス、表示名、権限、参加日時などです。
Q4. teams/{teamId}/tasks/{taskId} には何を保存しますか?
回答
そのチーム内のタスク情報を保存します。
たとえば、タスク名、説明、進行状況、優先度、担当者、作成者、作成日時などです。
このページのまとめ
- このページでは、Firestoreのデータ構造を整理した。
usersは、アプリを使うユーザーのプロフィールを保存する場所。teamsは、チーム情報を保存する場所。membersは、チームに参加している人と権限を保存する場所。tasksは、チーム内のタスクを保存する場所。membersとtasksは、teams/{teamId}の中に作る。memberIdsは、自分が参加しているチームを探しやすくするために使う。usersとmembersは役割が違う。usersは全体のユーザー情報。membersはチーム内での参加情報。- このページではnpmや環境変数は不要。
- 次のページでは、この構造を使ってチーム作成を作る。
次のページでやること
次のページでは、チーム作成機能を作ります。
teams/{teamId} と teams/{teamId}/members/{uid} を同時に作り、ログイン中のユーザーを自動で owner として登録します。
