View a markdown version of this page

$graphLookup - Amazon DocumentDB

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

$graphLookup

8.0.2 版的新功能。

Amazon DocumentDB $graphLookup 中的彙總階段會對集合執行遞迴搜尋。對於每個輸入文件, 會從一或多個值$graphLookup開始,並重複比對連線欄位與目標欄位,遵循相符文件鏈,直到沒有更多相符項目或達到選用的遞迴深度為止。這適用於周遊類似圖形或階層的資料,例如組織報告結構、類別樹或網路關係。

參數

  • from:遞迴搜尋的目標集合。from 集合必須位於相同的資料庫中。

  • startWith:指定用來開始遞迴搜尋之值的表達式。此值會與from集合中文件connectToField的 進行比較。如果 startWith評估為 陣列,則搜尋會同時從所有陣列元素執行。

  • connectFromField:其值用於連線到遞迴搜尋中下一個文件的欄位名稱。如果該值是陣列,則每個元素都會透過周遊個別追蹤。

  • connectToField:from集合中與 值相符的欄位名稱connectFromField。

  • as:新增至每個輸出文件的陣列欄位名稱。此欄位包含在遞迴搜尋期間找到的文件。如需這些文件順序的資訊,請參閱下列行為區段中的結果排序項目。

  • maxDepth:非負整數,指定初始查詢後要執行的遞迴反覆運算數目上限。此為選用參數。的值只會0執行初始比對,不會遞迴。如果您省略 maxDepth,搜尋會持續遞迴搜尋,直到沒有更多相符的文件為止。

  • depthField:要新增至as陣列中每個文件的欄位名稱,該文件包含找到文件的遞迴深度。此為選用參數。深度以 表示NumberLong,從零開始,因此初始查詢對應至深度 0。

  • restrictSearchWithMatch:指定套用至搜尋文件之其他比對條件的文件。此為選用參數。條件使用與$match階段相同的查詢語法,且不能包含彙總表達式。

注意

$graphLookup 階段受限於 100 MB 的記憶體限制,且不支援 allowDiskUse:true。超過此限制的操作會傳回錯誤。如果彙總包含其他階段,則這些階段allowDiskUse:true的選項仍然有效。

行為

  • 跨集合周遊:from設定為您要搜尋的集合。這可以是管道執行的相同集合,或相同資料庫中的不同集合。

  • 結果排序:as陣列中的文件不會以任何保證順序傳回。

範例 (MongoDB Shell)

下列範例使用 $graphLookup來周遊員工報告階層,並針對每個員工傳回上述的完整經理鏈。

下列命令會在 mongosh shell 中執行,插入建立報告階層的範例員工文件:

db.employees.insertMany([ { _id: 1, name: "Dev", reportsTo: "Eliot" }, { _id: 2, name: "Eliot", reportsTo: "Ron" }, { _id: 3, name: "Ron", reportsTo: "Andrew" }, { _id: 4, name: "Andrew", reportsTo: "Asya" }, { _id: 5, name: "Asya" } ]);

下列彙總會傳回新reportingHierarchy陣列中每個員工的完整管理鏈:

db.employees.aggregate([ { $graphLookup: { from: "employees", startWith: "$reportsTo", connectFromField: "reportsTo", connectToField: "name", as: "reportingHierarchy", depthField: "level" } } ]);

此操作會傳回下列輸出:

[ { _id: 1, name: 'Dev', reportsTo: 'Eliot', reportingHierarchy: [ { _id: 2, name: 'Eliot', reportsTo: 'Ron', level: 0 }, { _id: 3, name: 'Ron', reportsTo: 'Andrew', level: 1 }, { _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 2 }, { _id: 5, name: 'Asya', level: 3 } ] }, { _id: 2, name: 'Eliot', reportsTo: 'Ron', reportingHierarchy: [ { _id: 3, name: 'Ron', reportsTo: 'Andrew', level: 0 }, { _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 1 }, { _id: 5, name: 'Asya', level: 2 } ] }, { _id: 3, name: 'Ron', reportsTo: 'Andrew', reportingHierarchy: [ { _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 0 }, { _id: 5, name: 'Asya', level: 1 } ] }, { _id: 4, name: 'Andrew', reportsTo: 'Asya', reportingHierarchy: [ { _id: 5, name: 'Asya', level: 0 } ] }, { _id: 5, name: 'Asya', reportingHierarchy: [] } ]

每個員工文件都會取得陣列reportingHierarchy,其中包含遞迴比對的管理員文件。level 欄位會記錄找到每個管理員的遞迴深度。Asya 沒有reportsTo值,因此她的reportingHierarchy陣列是空的。

maxDepth 和 restrictSearchWithMatch (MongoDB Shell) 的範例

下列範例會周遊人員與 之間的連線網路maxDepth,以限制遞迴restrictSearchWithMatch,並僅包含符合其他條件的文件。搜尋會尋找起始人員的連線,最多兩個層級深度,只保留hobbies陣列包含 的人員golf。

下列命令在 mongosh shell 中執行,插入範例文件,其中每個人的friends點都透過單向連線鏈向前:

db.people.insertMany([ { _id: 1, name: "Tanya", friends: [ "Carole", "Shirley" ], hobbies: [ "tennis", "golf" ] }, { _id: 2, name: "Carole", friends: [ "Joseph" ], hobbies: [ "archery", "golf" ] }, { _id: 3, name: "Joseph", friends: [ "Angelo" ], hobbies: [ "tennis", "golf" ] }, { _id: 4, name: "Angelo", friends: [ "Miguel" ], hobbies: [ "travel", "golf" ] }, { _id: 5, name: "Miguel", friends: [], hobbies: [ "golf" ] }, { _id: 6, name: "Shirley", friends: [], hobbies: [ "frisbee" ] } ]);

下列彙總從 Tanya 開始,會周遊她的連線網路最多兩個層級深度,並僅保留列出golf為愛好的人員:

db.people.aggregate([ { $match: { name: "Tanya" } }, { $graphLookup: { from: "people", startWith: "$friends", connectFromField: "friends", connectToField: "name", as: "golfConnections", maxDepth: 2, restrictSearchWithMatch: { hobbies: "golf" } } }, { $project: { name: 1, "golfConnections.name": 1 } } ]);

此操作會傳回下列輸出:

[ { _id: 1, name: 'Tanya', golfConnections: [ { name: 'Carole' }, { name: 'Joseph' }, { name: 'Angelo' } ] } ]

只有hobbies陣列包含 的連線golf才會包含在內,而周遊會在兩個遞迴層級後停止。Shirley 會被排除,因為她未列出 golf,而 Miguel 會被排除,因為他離 Tanya 有三個關卡,超過 maxDepth的 2。由於連線形成的單向鏈永遠不會指向 Tanya,因此開始文件在遞迴搜尋期間不相符。

程式碼範例

若要檢視使用 MongoDB 驅動程式從第一個範例建置員工報告階層的程式碼範例,請選擇您要使用的語言標籤:

Node.js
const { MongoClient } = require('mongodb'); async function example() { const client = new MongoClient('mongodb://<username>:<password>@<cluster-endpoint>:27017/?tls=true&tlsCAFile=global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false'); try { await client.connect(); const db = client.db('test'); const employees = db.collection('employees'); const result = await employees.aggregate([ { $graphLookup: { from: 'employees', startWith: '$reportsTo', connectFromField: 'reportsTo', connectToField: 'name', as: 'reportingHierarchy', depthField: 'level' } } ]).toArray(); console.log(JSON.stringify(result, null, 2)); } catch (err) { console.error('Failed to run $graphLookup aggregation:', err.message); } finally { await client.close(); } } example();
Python
from pymongo import MongoClient from pymongo.errors import PyMongoError def example(): client = MongoClient('mongodb://<username>:<password>@<cluster-endpoint>:27017/?tls=true&tlsCAFile=global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false') try: db = client['test'] employees = db['employees'] pipeline = [ { "$graphLookup": { "from": "employees", "startWith": "$reportsTo", "connectFromField": "reportsTo", "connectToField": "name", "as": "reportingHierarchy", "depthField": "level" } } ] result = list(employees.aggregate(pipeline)) for doc in result: print(doc) except PyMongoError as error: print(f"Failed to run $graphLookup aggregation: {error}") finally: client.close() example()