単一の ObjectId ではなく ObjectId の配列であるフィールドに対して $lookup を実行するための構文は何ですか?
注文書の例:
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
]
}
機能しないクエリ:
db.orders.aggregate([
{
$lookup:
{
from: "products",
localField: "products",
foreignField: "_id",
as: "productObjects"
}
}
])
望ましい結果
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
],
productObjects: [
{<Car Object>},
{<Bike Object>}
],
}
ベストアンサー1
2017年アップデート
$lookup は配列をローカルフィールドとして直接使用できるようになりましたは$unwind
もう必要ありません。
古い回答
の$lookup
集計パイプライン ステージは、配列を直接操作することはできません。設計の主な目的は、関連する可能性のあるデータに対する「1 対多」タイプの結合 (または実際には「ルックアップ」) としての「左結合」です。ただし、値は配列ではなく単数形であることが意図されています。
$lookup
したがって、これを機能させるには、操作を実行する前にコンテンツを「非正規化」する必要があります。つまり、$unwind
:
db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
各配列メンバーにマッチした後、$lookup
結果は配列そのものなので、$unwind
再度$group
に$push
最終結果のための新しい配列。
見つからない「左結合」一致は、指定された製品の「productObjects」に対して空の配列を作成し、2 番目が$unwind
呼び出されたときに「product」要素のドキュメントを否定することに注意してください。
配列に直接適用できれば便利ですが、これは、単一の値を複数の可能な値と一致させることによって現在動作しているだけです。
基本的に非常に新しいため$lookup
、現在のところ、マングースそこで提供されている方法の「貧乏人バージョン」として.populate()
。違いは、$lookup
クライアントではなく が「結合」の「サーバー側」処理を提供することと、 で提供されている$lookup
ものから一部の「成熟度」が現在欠けていることです.populate()
(配列上で直接検索を補間するなど)。
これは実際に改善のために割り当てられた問題ですサーバー-22881運が良ければ、次のリリースかそのすぐ後のリリースでこの機能が使えるようになるでしょう。
設計原則として、現在の構造は良いことも悪いこともありませんが、単に「結合」を作成するときにオーバーヘッドが発生するだけです。そのため、MongoDB の当初の基本的な原則が適用されます。つまり、1 つのコレクションで「事前に結合された」データをそのまま使用できる場合は、そうすることが最善です。
一般原則として言えるもう 1 つのこと$lookup
は、ここでの「結合」の意図は、ここで示されているものとは逆の動作をすることです。したがって、他のドキュメントの「関連 ID」を「親」ドキュメント内に保持するのではなく、「関連ドキュメント」に「親」への参照が含まれている場合が、一般原則として最も効果的です。
したがって$lookup
、mongoose などがクライアント側の結合を実行する方法の逆である「リレーション デザイン」で「最もうまく機能する」と言えます。代わりに、各「多数」内の「1 つ」を識別することで、最初に配列.populate()
を必要とせずに、関連するアイテムを取得するだけです。$unwind