今回は、Firestore
を使ってフォロー機能を作る際にどんなdb設計にすればいいのかを紹介します。
Railsなどでフォロー機能を作る方法はいい記事が多く、それらを見ればいいのですが、NoSQL
でのフォロー機能に関してそんなに記事がなかったので今回記事を書こうと思いました。
ちなみに普通のdbでのフォロー機能の設計でとても参考になる記事を紹介するなら以下の記事です。めちゃくちゃわかりやすいです。
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸
フォロー機能の使い道
まず、今回僕が作成したアプリは各ユーザーが記事を投稿できるもので、フォローしたユーザーの投稿が一覧に表示されます。(Twitterみたいな感じです)
db設計
まず、フォロー機能を作るにしてもユーザーがいないと始まらないので、users
コレクションがあります。
それから、記事を管理するposts
コレクションがあります。
ここまでは普通ですね。
ここから本題のフォロー機能なのですが、Firestoreの場合、中間テーブルを作ってリレーションのようなことができません。
そこで、follows
コレクションをルートの階層(postsやusersと同じ階層)に作成します。
なぜルートの階層?
ルートの階層に作ると、後々色々なデータのやりとりやがしやすくなったり、読み取り回数が抑えられたりします。
userのデータのサブコレクションに保存するという方法もありますが、Firestoreではusersコレクションを読み取るたびにそのサブコレクションまで読み取ってしまいます。つまり、フォローの情報が全く関係ない読み取り(例えばuserの名前を表示するだけとか、userのidを取得するだけとか)を行いたいだけなのに、サブコレクションまで取得してしまい、読み取り回数up→コストがかかるということになります。
そこで、ルートの階層にfollows
コレクションを作ることで、フォローしている
、フォローされている
といった情報を持たせ、必要な時に必要な分だけデータを取得しようといった意図があります。
dbの中身はどうなっているのか
follows
コレクションの各ドキュメントの中身は以下のようになります。
フィールド名 | |
---|---|
following_uid | (任意のidなど) |
followed_uid | (任意のidなど) |
id | (任意のidなど) |
- following_uid:フォローしている人のuid
- followed_uid:フォローされている人のuid
- id:ドキュメントのidを保存
こんな感じです。これだけではわかりにくいので、例を挙げます。
例えば、uidが1の人がuid2の人をフォローする
というアクションをするとするなら、followsコレクションに保存されるデータは以下のようになります。
フィールド名 | |
---|---|
following_uid | 1 |
followed_uid | 2 |
id | (任意のidなど) |
uidが2の人がuid1の人をフォローする
であれば、
フィールド名 | |
---|---|
following_uid | 2 |
followed_uid | 1 |
id | (任意のidなど) |
となります。
フォローするという一つの行動
に対して1つのドキュメントが作成されます。「これって、フォローが起きるたびにデータ増えていくけどどうなの?」と初めは思いましたが、NoSQLはこれが正解っぽい(?)です。
firestoreでの多対多については、以下の記事でわかりやすくメリットデメリットを紹介されています。
Cloud Firestoreを実践投入するにあたって考えたこと
ここまで説明してきたように、rootの階層にfollowsコレクションを作ることで、タイムライン(フォローしてるユーザーの記事が表示される)を作るのであれば、follows
コレクションからログインしているユーザーのuidをfollowing_uid
に持つデータを
db.collection("follows")
.where("following_uid", "==", ログインしてるユーザのuid)
で取得しておいて、そのfollowed_uidとマッチする投稿を検索して表示するといった感じでできます。(投稿一つ一つにuidを持たせる必要がありますが)
以上です。
参考
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸