実行する必要のあるクエリのタイプと、各タイプが必要になる頻度を考慮する必要があります。私が似たようなことに取り組んでいたとき、私は6つの可能な行動を思いつきました:
- 親と何かをする
- 子供たちと何かをする
- 祖先(両親の両親、両親の両親の両親など)と何かをする
- 子孫(子供の子供、子供の子供の子供など)で何かをします
- 関係の変更(階層内のノードの追加/移動/削除)
- 現在のノードのメインデータを変更します(例:「タイトル」フィールドの値を変更します)
これらのそれぞれがアプリケーションにとってどれほど重要であるかを見積もる必要があります。
あなたの仕事のほとんどが、その直接の親と子を含む特定の記事の保存されたデータを扱うことを含む場合、最初のアイデア 最も便利です。実際、MongoDBでは、必要なすべての情報を外部から参照するのではなく、同じドキュメントに配置するのが一般的です。これにより、1つの情報を取得して、そのデータを操作するだけで済みます。ただし、リストの最後の4つのアクションはもっと注意が必要です。
特に、この場合、パスの最後のドキュメントしか気にしない場合でも、ツリーをトラバースして祖先と子孫を取得し、中間ドキュメントを移動してパスをたどる必要があります。これは、長い階層では遅くなる可能性があります。関係を変更するには、各ドキュメントにすべてのデータが存在するため、複数のドキュメント内で多くの情報を移動する必要があります。ただし、「タイトル」のような単一のフィールドを変更するだけでも、このフィールドがメインフィールドとして、または親フィールドまたは子フィールドの下に複数の異なるドキュメントに存在するという事実を考慮する必要があるため、煩わしい場合があります。
基本的に、あなたの最初のアイデア より多くの静的アプリケーションで最適に動作します 最初にデータを作成した後はデータをあまり変更しないが、定期的に読み取る必要がある場合。
MongoDBのドキュメントには、5つの推奨されるアプローチ があります。 ツリーのような(階層的な)構造を処理するため。それらはすべて異なる長所と短所がありますが、1つのドキュメントで更新するだけで、記事のメインデータを簡単に更新できます。
- 親の参照 :各ノードには、その親への参照が含まれています。
- 利点 :
- 高速の親ルックアップ(「_id」によるルックアップ=ドキュメントのタイトル、「親」フィールドを返す)
- 子の高速ルックアップ(「親」によるルックアップ=すべての子ドキュメントを返すドキュメントタイトル)
- 関係の更新は、「親」フィールドを変更するだけです
- 基になるデータを変更するには、1つのドキュメントのみを変更する必要があります
- 短所 :
- 祖先と子孫による検索は遅く、トラバーサルが必要です
- 子の参照 :各ノードには、その子への参照配列が含まれています
- 利点 :
- 子の高速取得(子配列を返す)
- 関係の高速更新(必要に応じて子の配列を更新するだけです)
- 短所 :
- 親を見つけるには、すべてのドキュメントのすべての子配列で_idを検索する必要があります(親には子として現在のノードが含まれるため)
- 祖先と子孫の検索には、ツリーの走査が必要です
- 利点 :
- 祖先の配列 :各ノードには、その祖先とその親の配列への参照が含まれています
- 利点 :
- 祖先の高速検索(特定の祖先を見つけるためにトラバーサルは必要ありません)
- 「親参照」アプローチに従って親と子を簡単に検索できます
- すべての子孫には同じ祖先が含まれている必要があるため、子孫を見つけるには、祖先を検索するだけです。
- 短所 :
- 関係に変更があった場合、多くの場合複数のドキュメント間で、祖先の配列と親フィールドを更新し続けることを心配する必要があります。
- 利点 :
- マテリアライズドパス :各ノードにはそれ自体へのパスが含まれています-正規表現が必要です
- 利点 :
- 正規表現を使用して子供や子孫を簡単に見つけることができます
- パスを使用して親と祖先を取得できます
- 部分パスによるノードの検索などの柔軟性
- 短所 :
- 関係の変更は、複数のドキュメントにわたるパスの変更が必要になる可能性があるため、困難です。
- 利点 :
- ネストされたセット :各ノードには、サブツリーの検索に役立つ「左」フィールドと「右」フィールドが含まれています
- 利点 :
- 「左」と「右」の間を検索することで、最適な方法で子孫を簡単に取得できます
- 「親リファレンス」アプローチと同様に、親と子を簡単に見つけることができます
- 短所 :
- 祖先を見つけるために構造をトラバースする必要があります
- 関係の変更は、他のどのオプションよりもパフォーマンスが低くなります。階層内で何かが変更された場合でも、「左」と「右」が意味をなすように、ツリー内のすべてのドキュメントを変更する必要がある場合があるためです。
- 利点 :
5つのアプローチについては、MongoDBドキュメント で詳しく説明されています。 。
あなたの2番目のアイデア 上記の「親参照」と「子参照」のアプローチを組み合わせたものです。このアプローチにより、子と親の両方を簡単に見つけることができ、関係と記事のメインデータを簡単に更新できます(ただし、親と子の両方のフィールドを更新する必要があります)が、それでもトラバースする必要があります祖先と子孫を見つけるために。
祖先と子孫を見つけることに興味がある場合(そして、関係を簡単に更新できることよりもこれに関心がある場合)、2番目のアイデアに祖先配列を追加して、祖先と子孫を簡単に照会できるようにすることを検討できます。もちろん、これを行うと、関係の更新は非常に困難になります。
結論:
-
最終的には、どのアクションが最も必要かによって異なります。基になるデータ(タイトルなど)が頻繁に変更される可能性がある記事を操作しているため、その記事のメインドキュメントだけでなく、すべての子ドキュメントと親。
-
2番目のアイデアは、直接の親と子を簡単に取得できるようにします。関係の更新もそれほど難しくありません(利用可能な他のオプションのいくつかよりも確かに優れています)。
-
関係を簡単に更新することを犠牲にして、祖先と子孫を簡単に見つけられるようにしたい場合は、祖先参照の配列を含めることを選択します。
-
一般に、必要なデータに到達するために何らかの反復または再帰を実行する必要があるため、必要なトラバーサルの数を最小限に抑えるようにしてください。関係を更新する機能を重視する場合は、ツリー内の変更するノードの数を減らすオプションも選択する必要があります(親参照、子参照、および2番目のアイデアでこれを実行できます)。