バージョン 3.4 で変更。
定義
$graphLookup再帰深度とクエリフィルターで検索を制限するオプションを使用して、コレクション内の再帰検索を実行します。
$graphLookup検索プロセスの概要を以下に示します。入力ドキュメントは、集計操作の
$graphLookupステージに入ります。$graphLookupfromパラメータで指定されたコレクションを検索対象とします(検索パラメータの完全なリストは以下を参照してください)。入力ドキュメントごとに、
startWithで指定された値から検索が始まります。$graphLookupstartWith値をfromコレクション内の他のドキュメントのconnectToFieldで指定されたフィールドと照合します。一致するドキュメントごとに、
$graphLookupはconnectFromFieldの値を取得し、fromコレクション内のすべてのドキュメントを確認し、一致するconnectToField値を探します。$graphLookupは、一致するたびにfromコレクション内の一致するドキュメントをasパラメータで指定された配列フィールドに追加します。この手順は、一致するドキュメントがなくなるまで、または操作が
maxDepthパラメータで指定された再帰深度に達するまで再帰的に続きます。$graphLookupにより、入力ドキュメントに配列フィールドが追加されます。すべての入力ドキュメントの検索が終わると、$graphLookupが結果を返します。
$graphLookupには、次のプロトタイプ形式があります。{ $graphLookup: { from: <collection>, startWith: <expression>, connectFromField: <string>, connectToField: <string>, as: <string>, maxDepth: <number>, depthField: <string>, restrictSearchWithMatch: <document> } } $graphLookup次のフィールドが含まれるドキュメントについて、フィールド説明from$graphLookupconnectFromFieldconnectToField操作で検索するターゲットコレクション。 を に再帰的に一致させます。fromコレクションはシャーディングできず、操作で使用する他のコレクションと同じデータベース内になければなりません。 詳細については、「 シャーディングされたコレクション 」を参照してください。startWith再帰検索を開始する
connectFromFieldの値を指定する式。オプションとして、startWithは値の配列であり、各値は走査プロセスを通じて個別に追跡されます。connectFromField$graphLookupconnectToFieldがコレクション内の他のドキュメントの と再帰的に一致するために使用する値を持つフィールド名。値が配列の場合、各要素は走査プロセスを通じて個別に追跡されます。connectToFieldconnectFromFieldパラメータで指定されたフィールドの値と一致する、他のドキュメント内のフィールド名。as各出力ドキュメントに追加される配列フィールドの名前。
$graphLookupドキュメントに到達するまでに ステージで走査されたドキュメントが含まれます。asフィールドに返されるドキュメントは、必ずしも任意の順序だとは限りません。maxDepth任意。 最大再帰深度を指定する負でない整数。
depthField任意。 検索パス内の走査済みドキュメントそれぞれに追加するフィールドの名前。このフィールドの値は当該ドキュメントの再帰深度で、
NumberLongと表されます。再帰深度の値はゼロから始まるため、最初の検索はゼロ深度となります。restrictSearchWithMatch
Considerations
シャーディングされたコレクション
fromで指定されたコレクションはシャーディングできません 。 ただし、 aggregate()メソッドを実行するコレクションはシャーディングできます。 つまり、次のようになります。
db.collection.aggregate([ { $graphLookup: { from: "fromCollection", ... } } ])
collectionはシャーディングできます。fromCollectionはシャーディングできません。
複数のシャーディングされたコレクションを結合するには、次の点を考慮してください。
$graphLookup集計ステージを使用する代わりに、クライアント アプリケーションを変更して手動検索を実行するようにします可能であれば、コレクションを結合する必要がない埋め込みデータモデルを使用します。
最大深度
maxDepthフィールドを0に設定することは、非再帰的な$graphLookup検索ステージと同じです。
メモリ
$graphLookup ステージは 100 メガバイトのメモリ制限内に収まる必要があります。aggregate() 操作に allowDiskUse: true が指定されている場合、$graphLookupステージではオプションは無視されます。aggregate() 操作に他のステージがある場合、allowDiskUse: true オプションはこれらの他のステージに対して有効になります。
詳細は「集計パイプラインの制限」を参照してください。
ビューと照合
複数のビューが関わる集計($lookup や $graphLookup など)が実行される場合、それらのビューには同じ照合が含まれる必要があります。
例
単一のコレクション内
employees という名前のコレクションには次のドキュメントが含まれています。
db.employees.insertMany( [ { _id: 1, name: "Dev" }, { _id: 2, name: "Eliot", reportsTo: "Dev" }, { _id: 3, name: "Ron", reportsTo: "Eliot" }, { _id: 4, name: "Andrew", reportsTo: "Eliot" }, { _id: 5, name: "Asya", reportsTo: "Ron" }, { _id: 6, name: "Dan", reportsTo: "Andrew" } ] )
次の$graphLookup 操作では、employees コレクションの reportsTo フィールドと name フィールドを再帰的に照合し、各人のレポート階層を返します。
db.employees.aggregate( [ { $graphLookup: { from: "employees", startWith: "$reportsTo", connectFromField: "reportsTo", connectToField: "name", as: "reportingHierarchy" } } ] )
この操作では、以下を返します。
{ _id: 1, name: "Dev", reportingHierarchy: [ ] } { _id: 2, name: "Eliot", reportsTo: "Dev", reportingHierarchy : [ { _id: 1, name: "Dev" } ] } { _id: 3, name: "Ron", reportsTo: "Eliot", reportingHierarchy: [ { _id: 2, name: "Eliot", reportsTo: "Dev" }, { _id: 1, name: "Dev" } ] } { _id: 4, name: "Andrew", reportsTo: "Eliot", reportingHierarchy: [ { _id: 2, name: "Eliot", reportsTo: "Dev" }, { _id: 1, name: "Dev" } ] } { _id: 5, name: "Asya", reportsTo: "Ron", reportingHierarchy: [ { _id: 2, name: "Eliot", reportsTo: "Dev" }, { _id: 3, name: "Ron", reportsTo: "Eliot" }, { _id: 1, name: "Dev" } ] } { "_id" : 6, "name" : "Dan", "reportsTo" : "Andrew", "reportingHierarchy" : [ { _id: 4, name: "Andrew", reportsTo: "Eliot" }, { _id: 2, name: "Eliot", reportsTo: "Dev" }, { _id: 1, name: "Dev" } ] }
次の表は、ドキュメント「{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }」の走査パスを示しています。
開始値 | ドキュメントの | |
深度 0 | | |
深度 1 | | |
深度 2 | |
出力により、階層「Asya -> Ron -> Eliot -> Dev」が生成されます。
複数のコレクションにわたる場合
$lookup と同様に、$graphLookup も同じデータベース内の別のコレクションにアクセスできます。
たとえば、2 つのコレクションを含むデータベースを作成します。
次のドキュメントを含む
airportsコレクション。db.airports.insertMany( [ { _id: 0, airport: "JFK", connects: [ "BOS", "ORD" ] }, { _id: 1, airport: "BOS", connects: [ "JFK", "PWM" ] }, { _id: 2, airport: "ORD", connects: [ "JFK" ] }, { _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ] }, { _id: 4, airport: "LHR", connects: [ "PWM" ] } ] ) 次のドキュメントを含む
travelersコレクション。db.travelers.insertMany( [ { _id: 1, name: "Dev", nearestAirport: "JFK" }, { _id: 2, name: "Eliot", nearestAirport: "JFK" }, { _id: 3, name: "Jeff", nearestAirport: "BOS" } ] )
travelers コレクションの各ドキュメントで次の集計操作を行った場合、airports コレクションの nearestAirport 値を検索し、connects フィールドと airport フィールドを再帰的に照合します。この操作では、最大再帰深度を 2 とします。
db.travelers.aggregate( [ { $graphLookup: { from: "airports", startWith: "$nearestAirport", connectFromField: "connects", connectToField: "airport", maxDepth: 2, depthField: "numConnections", as: "destinations" } } ] )
この操作は次の結果を返します。
{ _id: 1, name: "Dev", nearestAirport: "JFK", destinations: [ { _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ], numConnections: NumberLong(2) }, { _id: 2, airport: "ORD", connects: [ "JFK" ], numConnections: NumberLong(1) }, { _id: 1, airport: "BOS", connects: [ "JFK", "PWM" ], numConnections: NumberLong(1) }, { _id: 0, airport: "JFK", connects: [ "BOS", "ORD" ], numConnections: NumberLong(0) } ] } { _id: 2, name: "Eliot", nearestAirport: "JFK", destinations: [ { _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ], numConnections: NumberLong(2) }, { _id: 2, airport: "ORD", connects: [ "JFK" ], numConnections: NumberLong(1) }, { _id: 1, airport: "BOS", connects: [ "JFK", "PWM" ], numConnections: NumberLong(1) }, { _id: 0, airport: "JFK", connects: [ "BOS", "ORD" ], numConnections: NumberLong(0) } ] } { "_id" : 3, name: "Jeff", nearestAirport: "BOS", destinations: [ { _id: 2, airport: "ORD", connects: [ "JFK" ], numConnections: NumberLong(2) }, { _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ], numConnections: NumberLong(1) }, { _id: 4, airport: "LHR", connects: [ "PWM" ], numConnections: NumberLong(2) }, { _id:: 0, airport: "JFK", connects: [ "BOS", "ORD" ], numConnections: NumberLong(1) }, { _id:: 1, airport: "BOS", connects: [ "JFK", "PWM" ], numConnections: NumberLong(0) } ] }
次の表は、再帰的検索の走査パス(深度 2 まで)を示しています。開始 airport は JFK です。
開始値 |
| ||
深度 0 | | ||
深度 1 | | ||
深度 2 | |
クエリ フィルター付き
次の例では、人物の名前とその友人や趣味の配列が記載された一連のドキュメントを含むコレクションを使用しています。集計操作では、ある特定の人物を検索し、その人脈を走査して、趣味に golf を挙げている人を見つけます。
people という名前のコレクションには次のドキュメントが含まれています。
db.people.insertMany( [ { _id: 1, name: "Tanya Jordan", friends: [ "Shirley Soto", "Terry Hawkins", "Carole Hale" ], hobbies: [ "tennis", "unicycling", "golf" ] }, { _id: 2, name: "Carole Hale", friends: [ "Joseph Dennis", "Tanya Jordan", "Terry Hawkins" ], hobbies: [ "archery", "golf", "woodworking" ] }, { _id: 3, name: "Terry Hawkins", friends: [ "Tanya Jordan", "Carole Hale", "Angelo Ward" ], hobbies: [ "knitting", "frisbee" ] }, { _id: 4, name: "Joseph Dennis", friends: [ "Angelo Ward", "Carole Hale" ], hobbies: [ "tennis", "golf", "topiary" ] }, { _id: 5, name: "Angelo Ward", friends: [ "Terry Hawkins", "Shirley Soto", "Joseph Dennis" ], hobbies: [ "travel", "ceramics", "golf" ] }, { _id: 6, name: "Shirley Soto", friends: [ "Angelo Ward", "Tanya Jordan", "Carole Hale" ], hobbies: [ "frisbee", "set theory" ] } ] )
次の集計操作では、下記の 3 つのステージを使用します。
$matchは文字列"Tanya Jordan"を含むnameフィールドを持つドキュメントに一致します。1 つの出力ドキュメントを返します。$graphLookupは出力ドキュメントのfriendsフィールドをコレクション内の他のドキュメントのnameフィールドと接続して、Tanya Jordan'sの接続ネットワークを走査します。 このステージでは、restrictSearchWithMatchパラメータを使用して、hobbies配列にgolfが含まれるドキュメントのみを検索します。 1 つの出力ドキュメントを返します。$projectは、出力ドキュメントを形成します。connections who play golfのリスト内の名前は、入力ドキュメントのgolfers配列に挙げられているドキュメントのnameフィールドから取得されます。
db.people.aggregate( [ { $match: { "name": "Tanya Jordan" } }, { $graphLookup: { from: "people", startWith: "$friends", connectFromField: "friends", connectToField: "name", as: "golfers", restrictSearchWithMatch: { "hobbies" : "golf" } } }, { $project: { "name": 1, "friends": 1, "connections who play golf": "$golfers.name" } } ] )
この操作を実行すると次のドキュメントが返されます。
{ _id: 1, name: "Tanya Jordan", friends: [ "Shirley Soto", "Terry Hawkins", "Carole Hale" ], 'connections who play golf': [ "Joseph Dennis", "Tanya Jordan", "Angelo Ward", "Carole Hale" ] }