定義
$graphLookupバージョン5.1で変更。
再帰深度とクエリフィルターで検索を制限するオプションを使用して、コレクション内の再帰検索を実行します。
$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次のフィールドが含まれるドキュメントについて、フィールド説明fromTarget collection for the
$graphLookupoperation to search, recursively matching theconnectFromFieldto theconnectToField. Thefromcollection must be in the same database as any other collections used in the operation.シャーディングのサポートについては、「 シャーディングされたコレクション 」を参照してください。
startWithconnectFromField$graphLookupconnectToFieldがコレクション内の他のドキュメントの と再帰的に一致するために使用する値を持つフィールド名。値が配列の場合、各要素は走査プロセスを通じて個別に追跡されます。connectToFieldconnectFromFieldパラメータで指定されたフィールドの値と一致する、他のドキュメント内のフィールド名。as各出力ドキュメントに追加される配列フィールドの名前。ドキュメントに到達するまでに
$graphLookupステージで走査されたドキュメントが含まれます。asフィールドに返されるドキュメントは、必ずしも任意の順序だとは限りません。maxDepth任意。 最大再帰深度を指定する負でない整数。
depthField任意。 検索パス内の走査済みドキュメントそれぞれに追加するフィールドの名前。このフィールドの値は当該ドキュメントの再帰深度で、
NumberLongと表されます。再帰深度の値はゼロから始まるため、最初の検索はゼロ深度となります。restrictSearchWithMatch
Considerations
シャーディングされたコレクション
MongoDB5.1 以降では、from ステージの$graphLookup パラメーターでシャーディングされたコレクションを指定できます。
シャーディングされたコレクションをターゲットにしている間は、トランザクション内で $graphLookup ステージを使用できません。
最大深度
maxDepthフィールドを0 に設定することは、非再帰的な$graphLookup 検索ステージと同じです。
メモリ
$graphLookupステージは100 MB のメモリ制限内に収まる必要があります。allowDiskUse: true aggregate()操作に が指定されている場合、$graphLookup ステージはオプションを無視します。aggregate() 操作に他のステージがある場合、allowDiskUse: true オプションはこれらの他のステージに対して有効になります。
詳細については、集計パイプラインの制限を参照してください。
ソートされていない結果
$graphLookup ステージではソートされた結果は返されません。結果を並べ替えるには、$sortArray 演算子を使用します。
ビューと照合
複数のビューが関わる集計($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 操作では、reportsTo nameemployeesコレクションの フィールドと フィールドを再帰的に照合し、各人のレポート階層を返します。
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: 2, name: 'Eliot', reportsTo: 'Dev' }, { _id: 1, name: 'Dev' }, { _id: 4, name: 'Andrew', reportsTo: 'Eliot' } ] } ]
次の表は、ドキュメント「{ "_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: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('0') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('1') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('2') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('1') } ] }, { _id: 2, name: 'Eliot', nearestAirport: 'JFK', destinations: [ { _id: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('0') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('1') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('2') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('1') } ] }, { _id: 3, name: 'Jeff', nearestAirport: 'BOS', destinations: [ { _id: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('1') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('0') }, { _id: 4, airport: 'LHR', connects: [ 'PWM' ], numConnections: Long('2') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('1') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('2') } ] } ]
次の表は、再帰的検索の走査パス(深度 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は、string"Tanya Jordan"を含むnameフィールドを持つ document と一致します。1 つの出力 document を返します。$graphLookupconnects the output document'sfriendsfield with thenamefield of other documents in the collection to traverseTanya Jordan'snetwork of connections. This stage uses therestrictSearchWithMatchparameter to find only documents in which thehobbiesarray containsgolf. Returns one output document.$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': [ 'Tanya Jordan', 'Joseph Dennis', 'Angelo Ward', 'Carole Hale' ] } ]
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" }
次の Employeeクラスは、employeesコレクション内のドキュメントをモデル化します。
[] public class Employee { [] public int Id { get; set; } [] public string Name { get; set; } = null!; [] public string? ReportsTo { get; set; } [] public List<string> Hobbies { get; set; } = new(); [] public List<Employee> ReportingHierarchy { get; set; } = new(); }
To use the MongoDB .NET/C# driver to add a $graphLookup stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
次の例では、employeesコレクションの ReportsTo フィールドと Name フィールドを再帰的に照合するパイプラインステージを作成し、各人のレポート階層を返します。
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy);
AggregateGraphLookupOptionsオブジェクトを使用して、再帰する深度と深度フィールドの名前を指定できます。次のコード例では、前の例と同じ $graphLookup操作を実行しますが、最大再帰深度は に指定しています。1
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy, new AggregateGraphLookupOptions<Employee, Employee, Employee> { MaxDepth = 1 });
また、AggregateGraphLookupOptionsオブジェクトを使用して、 MongoDB が検索にドキュメントを含めるために一致する必要があるフィルターを指定することもできます。次のコード例では、前の例と同じ $graphLookup操作を実行しますが、Hobbiesフィールドに "golf" が含まれる Employee ドキュメントのみが含まれます。
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy, new AggregateGraphLookupOptions<Employee, Employee, Employee> { MaxDepth = 1, RestrictSearchWithMatch = Builders<Employee>.Filter.AnyEq( e => e.Hobbies, "golf") });
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" } ]);
MongoDB Node.jsドライバーを使用して $graphLookup ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $graphLookup 演算子を使用します。
次の例では、reportsTo フィールドを employees コレクションの name フィールドと再帰的に照合するパイプラインステージを作成し、reportingHierarchy という名前の新規フィールドに各人のレポート作成階層を返します。次に、この例は集計パイプラインを実行します。
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
再帰の深さを指定するには、maxDepth フィールドを使用します。次のコード例は、前の例と同じ$graphLookup 操作を実行しますが、最大再帰深度を 1 に指定します。
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy", maxDepth: 1 } } ]; const cursor = collection.aggregate(pipeline); return cursor;
操作でドキュメントが検索結果に含まれるために一致する必要があるフィルターを指定するには、restrictSearchWithMatch フィールドを使用します。次のコード例では、前の例と同じ $graphLookup 操作を実行しますが、hobbiesフィールドに "golf" が含まれる employee ドキュメントのみを含みます。
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy", maxDepth: 1, restrictSearchWithMatch: { hobbies: "golf" } } } ]; const cursor = collection.aggregate(pipeline); return cursor;
詳細
To learn more about how to use $graphLookup, see Working with Graph Data in MongoDB.