これは、過剰埋め込みの問題とその対処方法を説明する良い質問です。
例:いいねを投稿
簡単な例である、投稿を好むユーザーの例に固執しましょう。他の関係はそれに応じて処理する必要があります。
投稿内にいいねを保存すると、遅かれ早かれ、非常に人気のある投稿がサイズ制限に達するという問題が発生することは間違いありません。
したがって、正しくフォールバックしてpost_likes
を作成しました コレクション。なぜこれを正しいと呼ぶのですか?ユースケースと機能要件および非機能要件に適合するためです!
- それは無期限にスケーリングします(まあ、理論的な限界はありますが、それは巨大です)
- 保守は簡単です(
post_id
上に一意のインデックスを作成します) およびliked_user_id
)と使用(ユーザーと投稿の両方がわかっているので、いいねを追加するのは単純な挿入またはアップサートである可能性が高い) - どのユーザーがどの投稿を高く評価し、どの投稿がどのユーザーに高く評価されているかを簡単に見つけることができます
ただし、頻繁に発生する特定のユースケースに対する不要なクエリを防ぐために、コレクションを少し拡張します。
今のところ、投稿のタイトルとユーザー名は変更できないと仮定しましょう。その場合、次のデータモデルの方が理にかなっている可能性があります
{
_id: new ObjectId(),
"post_id": someValue,
"post_title": "Cool thing",
"liked_user_id": someUserId,
"user_name": "JoeCool"
}
ここで、投稿を高く評価したすべてのユーザーのユーザー名を表示するとします。上記のモデルでは、それは単一の、かなり高速なクエリになります:
db.post_likes.find(
{"postId":someValue},
{_id:0,user_name:1}
)
IDのみが保存されている場合、このかなり通常のタスクには少なくとも2つのクエリが必要であり、投稿には無限の数のいいねが存在する可能性があるという制約があるため、巨大になる可能性があります。 メモリ消費量(ユーザーIDをRAMに保存する必要があります)。
確かに、これはある程度の冗長性につながりますが、何百万人もの人々が投稿を好む場合でも、多くのパフォーマンスを獲得しながら、数メガバイトの比較的安価な(そして拡張が容易な)ディスクスペースについて話しているだけです。 ユーザーエクスペリエンスの観点から。
ここで、ユーザー名と投稿タイトルが変更される可能性がある場合でも、複数の更新を行うだけで済みます。
db.post_likes.update(
{"post_id":someId},
{ $set:{ "post_title":newTitle} },
{ multi: true}
)
非常に頻繁に発生するユースケースのユーザー名や投稿を非常に高速に変更するなど、かなりまれな作業を行うには時間がかかると取引しています。
結論
MongoDBはドキュメント指向のデータベースであることに注意してください。したがって、関心のあるイベントを将来のクエリに必要な値で文書化し、それに応じてデータをモデル化します。