Docs Menu
Docs Home
/
MongoDBマニュアル
/ / /

$graphLookup(集計)

項目一覧

  • 定義
  • Considerations
  • 追加リソース
$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

$graphLookup 操作で検索するターゲット コレクション。connectFromFieldconnectToField に再帰的に一致させます。from コレクションは、操作で使用する他のコレクションと同じデータベース内になければなりません。

MongoDB 5.1 以降では、fromパラメータで指定されたコレクションをシャーディングできます。

startWith
再帰検索を開始する connectFromField の値を指定する。オプションとして、 startWith は値の配列であり、各値は走査プロセスを通じて個別に追跡されます。
connectFromField
$graphLookupがコレクション内の他のドキュメントのconnectToFieldと再帰的に照合するために使用する値を持つフィールド名。 値が配列の場合、各要素は走査プロセスを通じて個別に追跡されます。
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 メガバイトのメモリ制限内に収まる必要があります。aggregate() 操作に allowDiskUse: true が指定されている場合、$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 操作では、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" }」の走査パスを示しています。

開始値

ドキュメントの 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: 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 まで)を示しています。開始 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は文字列 "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"
]
}

ウェビナー: MongoDB でのグラフデータの操作

戻る

$geoNear