質問: サーバサイドにmBaaSを使用して、SNSのようなスマートフォンアプリを作ろうと思っています。 使おうと思っているmBaaSのデータストア(DB)がmongoDBで実装されているため、NoSQLの特性を考慮してスキーマ設計を行う必要がある状況です。 本題ですが、 SNSにおけるフォロー、フォロワーのような関係をどのように実現するかで詰まってしまいました。 RDBのように中間テーブルを設ける場合も、ユーザーテーブルに配列形式でフォロー、フォロワーのカラムを設ける場合も、どちらも整合性の観点でトランザクション処理が必要になると思いますが、mongoDBにはトランザクション処理に対応していないはずです。 ユーザーテーブルに「フォロー」カラムのみ設けた場合、トランザクションは不要になりますが、この場合「フォロワー」に関する情報を扱うのが大変難しくなりそうだと思いました。(フォロワー数を調べるために全ユーザーのフォローカラムのレコードを調べる必要がある) この問題をクリアする解決策はありますでしょうか。
回答: たとえば、次のようなスキーマが考えられると思います。 ``` { "followee": 1024, "follower": 1025, "start": ISODate("2017-01-11T11:12:00") } ``` ここで`followee`は被フォローユーザ、`follower`はフォローしているユーザのIDです。つまり、フォロー-被フォロー関係のひとつひとつにドキュメントを作ります。そして、各ユーザ固有の情報についてはユーザ毎に別のドキュメントを作ります。 個々のユーザのドキュメントに配列で全てのフォロー情報を持たせるようなことをすると、要素数が多くなったときにメモリ使用や速度の効率が悪くなります。それにご質問でおっしゃっているように、フォロー情報は簡単に取れても被フォローの情報を取るのは難しくなります。一般的に言って、少数の情報だけを含む**小さなドキュメント**をたくさん作ることは有用です。 ところで、RDBではトランザクションによって更新の同時性を保証しようとしますが、多くのNoSQLにはそのような仕組みがありません。さらにシャーディングやレプリケーションを行っていれば、更新が反映されるまでのタイムラグはノード毎に変動します。同時性が揺らぐわけで、データの厳密な整合性は保証されないとも言えます。 上で述べた方法はRDBでのリンクテーブルに似ていますが、トランザクションがない以上、整合性は保証されません (たとえば、あるユーザが退会した瞬間に別のユーザがフォロワ一覧を取得すると、不完全なユーザ情報が取れるかもしれません)。そういうことは**気にしない**ようにアプリを作る必要があります (たとえば、不完全な情報は無視するなど)。SNSなどのアプリでは、多少の不整合は許されることが多いかもしれません。 逆に言うと、トランザクションを必要とするような厳密な整合性を要求するシステムでは、RDBを使うべきです。