【Firebase】Firestore(NoSQL)でのデータベース設計の基本 と RDBとの設計方法の違い について

本記事のテーマ

  • Firestore(NoSQL)でのデータベース設計の基本
  • RDB との設計方法の違い

対象の読者

  • Firestore を触り始めたけど、設計方法がわからないという方
  • RDB(Oracle, SQLServer, MySQL)との設計方法の違いについて知りたい方

前提事項

必須

  • Firestore を触ったことがある
  • もしくは ドキュメント型の NoSQL について知っている。触ったことがある

知っていればなお良い

  • RDB(リレーショナルデータベース)での設計方法

本記事を書く理由

学んだ内容のアウトプット

筆者が誤った解釈をしている場合があります

その際はご指摘願います

掲示板アプリを想定した設計を考えてみる

アプリ概要

  • 全ユーザの投稿内容が参照できる
  • それぞれのユーザは投稿を行うことができる(投稿数に制限なし)

※本記事の説明では、既ににユーザ認証が完了しているものとする。

必要なエンティティ

  • ユーザ・・・ユーザを管理する
  • 投稿 ・・・ユーザが投稿した内容を管理する

今回はとてもシンプルなアプリなので2つのエンティティとなる。

ここから2つのエンティティの関連付けを行っていくわけだが、RDBとFirestoreではDB設計方法に大きな違いがあるらしい。

この、設計方法の違いについて深掘りしていく。

エンティティ関連(E-R)図

ここまでを整理すると、以下のアプリ要件となる。

  • 1人のユーザは全ユーザの投稿内容を一覧表示で参照することができる
  • 1人のユーザは複数の投稿をすることができる

そして、RDBとFirestoreには以下の違いがある。

RDB Firestore
サーバーサイドジョイン可否 ○(可能。INNER JOIN や LEFT JOINなどが該当) ×(クライアントサイドジョインが発生する)

これらを踏まえて、簡単なDB設計を行うと、

パターンA(正規形)

RDBでは一般的になっている正規化を行うパターン。
Firestoreでも実現可能。だが、クライアント側で結合が必要。

トップレベルでのコレクション(テーブル)管理となる。

パターンB(非正規形)

ここで、Firestoreに慣れていない人が気になるのが、postsコレクションが2つ存在しているということ。

画像右上のpostsコレクションは全ユーザの投稿内容を保持しており、
画像中央のPostsコレクションは1人のユーザの投稿内容のみを保持している。

トップレベル管理 or サブコレクション管理

  • サブコレクションは、ある特定のユーザだけが見れたり編集したいデータの置き場に使用する
    セキュリティルールが簡単に書ける
  • トップレベルコレクションは、みんなが見えるデータを保持することに向いている

再帰形のトップレベル管理

例えば、以下の要件が追加になったとする。

  • 投稿に匿名で返信できるようにする

その場合は、以下のような自分で自分を参照する(再帰)設計が良さそう。

parentPostIdを用いて階層を管理すれば良さそう。

/// 親(返信元)の投稿ID 
/// nullの場合は最初の投稿を表す 
String? parentPostId;

あとは、自分の投稿は投稿後に編集可能にするため、トップレベルのコレクションにあるとセキュリティ的に心配だったりする場合は、

User 
┗ UserPosts<List> PublicPosts

といった感じで、サブコレクションとトップレベルコレクションの2つを用意する。

そして、UserPostsが作成/更新されたら、Cloud Functionsを発火させてPublicPostを作成/更新するようにする方法もあるらしい。

サブコレクション管理 or リスト管理

Firestoreで非正規形中心の設計を行う場合、データ群をサブコレクションとして扱うのか、コレクション中のリストとして扱うのかを検討する場面にも遭遇する。

例えば、あるアプリで以下の要件が追加されたとする。

  • hogeコレクションのドキュメントに履歴を持たせる

サブコレクション管理での設計

データ構造
Hoge 
┣ id 
┣ fuga 
┗ HogeHistorys<List<Hoge>>

リスト管理での設計

データ構造
Hoge 
┣ id 
┣ fuga 
┗ history<List<Map(String, Object)>> 
  ┣ "id" : "a" 
  ┗ "fuga" : "fugafuga" 
. 
. 
. 
. 
.

サブコレクション管理とリスト管理の違い

Firestoreは1ドキュメントにつき1Mbが最大容量

このルールを踏まえると

  • サブコレクションは、永続的にデータが増えていくような場合に向いている
  • リスト管理は、データ量があらかじめ決まっている場合に向いている

参考記事