元々Firestoreを使いこなせてない感がすごくあったので、改めて学習し直して新設計にマイグレーションしようとしているので、その辺の実装について記事にしていきます。
まず、現状のFirestoreの設計が以下です。
現状の Firestoreの設計(悪い例)
├──users/:id ├──calendars/:id ├──items/:id ├──itemDetails/:id └──expoPushTokens/:id
Firestoreの性質を理解してなかったこともありRDBっぽい設計になっていました。 こういう設計にしていると、Firestoreのwhere-inは双方10件までしか取得できないという制限があるため、inを使用したクエリを複数回分けて実行するなど、非常に面倒な実装をすることになります。
また、こういう設計にせずともCollectionGroupを使用することで、同じようなデータは取得できるので上記のような設計にするメリットは、ほぼ無いと思います。
ということで、以下のようなにFirestoreの構造を設計し直しました。
Firestoreの新設計
/version/1/users/:id ├──expoPushTokens/:id └──calendars/:date └──items/:id └──itemDetails/:id
以下、新設計の説明
versionを設定することで今後、設計変更が起きた時にバージョンを上げて対応できるように修正
version/1
データは全てusersに紐づくため先頭に設計
users/:id ├──expoPushTokens/:id └──calendars/:date
予定のデータはカレンダーに紐づくように修正してcalendars(日付情報)→items(メインの予定情報)→itemDetails(各予定の詳細情報)としました。 またcalendarsのドキュメントのIDはdate(日付)で設定する設計に変更(1日1スケジュールの関係なので)
calendars/:date └──items/:id └──itemDetails/:id
こちらの設計にすることでアプリ内で自身のユーザーのカレンダーの情報が欲しい時は以下にアクセスすれば取得できます。
version/1/users/:id/calendars
また、2020年1月1日の予定を取得するには以下
version/1/users/:id/calendars/2020-01-01/items
2020年1月1日の予定の詳細を取得するには以下になります。
version/1/users/:id/calendars/2020-01-01/items/:id/itemDetails/:id
と、このようにユーザー起点でデータを取得するのが非常にシンプルになりました。
また、ユーザー間を超えてデータを取得したい場合は、CollectionGroupを使用して以下のように取得します。
例)バッチ処理でPush通知を送るため、全ユーザーで2020年1月1日の予定を取得する必要がある
CollectionGroup("calendars").Where("date" "==" "2020-01-01")
これで各usersの配下にあるcalendarsを1まとめにして検索することができます。
と、こんな感じで使用することができ、Firestoreらしい設計に変更できたかなと思います。
既存データのマイグレーションは以下のスクリプトで実装しています。
また、新設計に合わせてbackendの方も書き換え中なので、その辺が実装が終わったら、また記事に使用と思います