AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。
Docs Menu

$graphLookup(集計ステージ)

$graphLookup

バージョン5.1で変更。

再帰深度とクエリフィルターで検索を制限するオプションを使用して、コレクション内の再帰検索を実行します。

$graphLookup 検索プロセスの概要を以下に示します。

  1. 入力ドキュメントは、集計操作の $graphLookup ステージに入ります。

  2. $graphLookup from パラメータで指定されたコレクションを検索対象とします(検索パラメータの完全なリストは以下を参照してください)。

  3. 入力ドキュメントごとに、startWith で指定された値から検索が始まります。

  4. $graphLookup startWith 値を from コレクション内の他のドキュメントの connectToField で指定されたフィールドと照合します。

  5. 一致するドキュメントごとに、 $graphLookupconnectFromField の値を取得し、 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

Target collection for the $graphLookup operation to search, recursively matching the connectFromField to the connectToField. The from collection must be in the same database as any other collections used in the operation.

シャーディングのサポートについては、「 シャーディングされたコレクション 」を参照してください。

startWith

再帰検索を開始する の値を指定する 式 。connectFromFieldstartWith が配列と評価される場合、$graphLookup はすべての配列要素から同時に検索を実行します。

connectFromField

$graphLookupconnectToFieldがコレクション内の他のドキュメントの と再帰的に一致するために使用する値を持つフィールド名。値が配列の場合、各要素は走査プロセスを通じて個別に追跡されます。

connectToField

connectFromField パラメータで指定されたフィールドの値と一致する、他のドキュメント内のフィールド名。

as

各出力ドキュメントに追加される配列フィールドの名前。ドキュメントに到達するまでに$graphLookup ステージで走査されたドキュメントが含まれます。

as フィールドに返されるドキュメントは、必ずしも任意の順序だとは限りません。

maxDepth

任意。 最大再帰深度を指定する負でない整数。

depthField

任意。 検索パス内の走査済みドキュメントそれぞれに追加するフィールドの名前。このフィールドの値は当該ドキュメントの再帰深度で、NumberLong と表されます。再帰深度の値はゼロから始まるため、最初の検索はゼロ深度となります。

restrictSearchWithMatch

任意。 再帰検索の追加条件を指定するドキュメント。構文はクエリフィルターの構文と同じです。

このフィルターでは集計式を使用できません。たとえば、次のドキュメントを使用して、lastName 値が入力ドキュメントの lastName 値と異なるドキュメントを検索することはできません。

{ lastName: { $ne: "$lastName" } }

"$lastName" はフィールドパスではなく文字列リテラルとして機能するため、このコンテキストではドキュメントを使用できません。

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" }」の走査パスを示しています。

開始値

ドキュメントの reportsTo 値:

{ ... reportsTo: "Ron" }

深度 0

{ _id: 3, name: "Ron", reportsTo: "Eliot" }

深度 1

{ _id: 2, name: "Eliot", reportsTo: "Dev" }

深度 2

{ _id: 1, name: "Dev" }

出力により、階層「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 まで)を示しています。開始 airportJFK です。

開始値

travelers コレクションの nearestAirport 値:

{ ... nearestAirport: "JFK" }

深度 0

{ _id: 0, airport: "JFK", connects: [ "BOS", "ORD" ] }

深度 1

{ _id: 1, airport: "BOS", connects: [ "JFK", "PWM" ] }
{ _id: 2, airport: "ORD", connects: [ "JFK" ] }

深度 2

{ _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ] }

次の例では、人物の名前とその友人や趣味の配列が記載された一連のドキュメントを含むコレクションを使用しています。集計操作では、ある特定の人物を検索し、その人脈を走査して、趣味に 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 を返します。

  • $graphLookup connects the output document's friends field with the name field of other documents in the collection to traverse Tanya Jordan's network of connections. This stage uses the restrictSearchWithMatch parameter to find only documents in which the hobbies array contains golf. 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コレクション内のドキュメントをモデル化します。

[BsonIgnoreExtraElements]
public class Employee
{
[BsonId]
public int Id { get; set; }
[BsonElement("name")]
public string Name { get; set; } = null!;
[BsonElement("reportsTo")]
public string? ReportsTo { get; set; }
[BsonElement("hobbies")]
public List<string> Hobbies { get; set; } = new();
[BsonElement("reportingHierarchy")]
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.

このページを評価