問題
「全体」として定義されたドキュメントを、全体とその部分の両方がクエリ可能な「部分」の小さな固定コレクションにモデル化する必要があります。
スライスしたパイは、私が必要とするモデルの良い例です。ドメインについてさらに説明します。
- pie:slice には 1:多 (1-10) の関係があります。各スライスは 1 つのパイにのみ属し、各パイには 1 ~ 10 のスライスがあります。
- この例では、パイは作成時にスライスされ、スライスの数は変わらないと仮定します。
- パイは常にそのスライスで照会されます。逆は必ずしも真ではありませんが、クエリされたスライスは円に関するメタデータにアクセスする必要があります
- 例として、"weight" がスライスの唯一のプロパティであるとします。すべてのスライスで共有されるメタデータは、各スライスのメタデータよりもはるかに大きくなります。すべてのスライスのパン、フィリング、クラスト、キッチンなどは同じです。すべてのデータを各スライスに複製する必要がないことが理想的です。
- スライスとパイの両方が効率的にクエリ可能であり、パイ全体の属性またはスライスの属性によってソート可能でなければなりません。例:
- ちょうど 2 切れのパイをすべて見つける
- スライスの重さが 10 オンスを超えるすべてのパイを見つける
- タイプが「cherry」のすべてのスライスを検索します
- すべてのパイで最も重い 5 つのスライスを見つける
質問:
上記のポイントを考えると、どのようにして 1 つのモデルpie
をslices
効率的にクエリ可能にする (そして可能であれば効率的に格納する) ことができるでしょうか?
これが明らかな場合は、回答してください。これまでに試した 2 つのアプローチと、どちらも満足できない理由について説明します。
私が試したこと:
1.埋め込み
全体の中に部分を埋め込むのは当然の選択のように思えた。
Pie {
type: String, // `type` and other shared attrs are defined on Pie
slices: [{
_id: ObjectId
weight: Number
}]
}
これにより、タイプ、重量、スライスの重量でパイをクエリできaggregate
、 、unzip
、およびを介して個々のチェリー パイ スライスをクエリできますproject
。
問題は、個々のスライスをソートしてクエリする方法にあります。たとえば、すべてのパイから 5 つの最も重いスライスを取得する必要があるとします (上記の問題で説明したように)。これは集計で可能ですが、方法がわかりません。
2. コレクションを分ける
最初のスキーマをあきらめた後、参照 ID で結合された 2 つの個別のコレクションを使用することに戻りました。
Pie {
type: String // `type` and other shared attrs are defined on Pie ...
}
Slice {
pie_id: ObjectId,
type: String, // ... and duplicated to all slices
weight: Number
}
これでクエリの問題は解決しますが、さらにいくつかの問題が発生します。ここでtype
は複製されているだけです。私の実際のアプリケーションでは、これははるかに悪く、私のアナログSlice
はおそらく 90% 重複データです。
もう 1 つの問題は、パイを照会するたびに、すべてのスライスを再度照会する必要があることです。さらに、パイの作成はアトミック操作ではなく、個別の挿入のバッチです。