$graphLookup(集計)
定義
$graphLookup
バージョン 5.1 での変更。
再帰深度とクエリフィルターで検索を制限するオプションを使用して、コレクション内の再帰検索を実行します。
$graphLookup
検索プロセスの概要を以下に示します。入力ドキュメントは、集計操作の
$graphLookup
ステージに入ります。$graphLookup
from
パラメータで指定されたコレクションを検索対象とします(検索パラメータの完全なリストは以下を参照してください)。入力ドキュメントごとに、
startWith
で指定された値から検索が始まります。$graphLookup
startWith
値を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
$graphLookup
操作で検索するターゲット コレクション。connectFromField
をconnectToField
に再帰的に一致させます。from
コレクションは、操作で使用する他のコレクションと同じデータベース内になければなりません。MongoDB 5.1 以降では、
from
パラメータで指定されたコレクションをシャーディングできます。startWith
connectFromField
$graphLookup
がコレクション内の他のドキュメントのconnectToField
と再帰的に照合するために使用する値を持つフィールド名。 値が配列の場合、各要素は走査プロセスを通じて個別に追跡されます。connectToField
connectFromField
パラメータで指定されたフィールドの値と一致する、他のドキュメント内のフィールド名。as
各出力ドキュメントに追加される配列フィールドの名前。 ドキュメントに到達するまでに
$graphLookup
ステージで走査されたドキュメントが含まれます。as
フィールドに返されるドキュメントは、必ずしも任意の順序だとは限りません。maxDepth
任意。 最大再帰深度を指定する負でない整数。depthField
任意。 検索パス内の走査済みドキュメントそれぞれに追加するフィールドの名前。このフィールドの値は当該ドキュメントの再帰深度で、NumberLong
と表されます。再帰深度の値はゼロから始まるため、最初の検索はゼロ深度となります。restrictSearchWithMatch
Considerations
シャーディングされたコレクション
MongoDB5.1 以降では、from
ステージの パラメーターで$graphLookup
シャーディングされたコレクション を指定できます。
シャーディングされたコレクションをターゲットにしている間は、トランザクション内で $graphLookup
ステージを使用できません。
最大深度
maxDepth
フィールドを0
に設定することは、非再帰的な$graphLookup
検索ステージと同じです。
メモリ
$graphLookup
ステージは 100 メガバイトのメモリ制限内に収まる必要があります。aggregate()
操作に allowDiskUse: true
が指定されている場合、$graphLookup
ステージではオプションは無視されます。aggregate()
操作に他のステージがある場合、allowDiskUse: true
オプションはこれらの他のステージに対して有効になります。
詳細は「集計パイプラインの制限」を参照してください。
ソートされていない結果
$graphLookup
ステージではソートされた結果は返されません。結果を並べ替えるには、$sortArray
演算子を使用します。
ビューと照合
複数のビューが関わる集計($lookup
や $graphLookup
など)が実行される場合、それらのビューには同じ照合が含まれる必要があります。
例
単一のコレクション内
employees
という名前のコレクションには次のドキュメントが含まれています。
{ "_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
という名前のコレクションには次のドキュメントが含まれています。
{ "_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" ] }