Tôi tin rằng có cấp độ trường chúng ta có thể xây dựng cấu trúc phân cấp từ một mảng bằng cách sử dụng $ Reduce. Để đạt được điều đó, chúng ta cần có reportees
được sắp xếp theo cấp độ giảm dần sau $graphLookup
. Thật không may, cách duy nhất để làm điều đó hiện tại là sử dụng nhóm $ unwind + $ sort + $, điều này làm cho việc tổng hợp khá dài.
Sau đó, chúng tôi có thể xử lý mảng được sắp xếp đó bằng cách sử dụng $reduce
. Trong mỗi bước, chúng tôi chỉ cần thêm một nhân viên vào tập kết quả bao gồm reportees
của anh ta từ cấp độ trước. Ngoài ra, chúng tôi cần phát hiện khi nào level
các thay đổi trong quá trình xử lý của chúng tôi và sắp xếp lại các mảng trợ giúp trong trường hợp đó.
$ addFields chỉ cần thay thế reportees
trong trường hợp này. $ concatArrays cho phép chúng tôi thêm nhân viên hiện tại ($$this
) đến kết quả. Sử dụng bộ lọc $, chúng tôi có thể nhận được reportees
từ cấp thấp hơn.
db.getCollection('employees').aggregate([
{
$match: {
empId : "10"
}
},
{
$graphLookup: {
from: "employees",
startWith: "$empId",
connectFromField: "empId",
connectToField: "managerId",
as: "reportees",
maxDepth: 4,
depthField: "level"
}
},
{
$project: {
"empId":1,
"managerId":1,
"reportees.empId":1,
"reportees.name":1,
"reportees.managerId":1,
"reportees.level":1
}
},
{
$unwind: "$reportees"
},
{
$sort: { "reportees.level": -1 }
},
{
$group: {
_id: "$_id",
empId: { $first: "$empId" },
managerId: { $first: "$managerId" },
reportees: { $push: "$reportees" }
}
},
{
$addFields: {
reportees: {
$reduce: {
input: "$reportees",
initialValue: {
currentLevel: -1,
currentLevelEmployees: [],
previousLevelEmployees: []
},
in: {
$let: {
vars: {
prev: {
$cond: [
{ $eq: [ "$$value.currentLevel", "$$this.level" ] },
"$$value.previousLevelEmployees",
"$$value.currentLevelEmployees"
]
},
current: {
$cond: [
{ $eq: [ "$$value.currentLevel", "$$this.level" ] },
"$$value.currentLevelEmployees",
[]
]
}
},
in: {
currentLevel: "$$this.level",
previousLevelEmployees: "$$prev",
currentLevelEmployees: {
$concatArrays: [
"$$current",
[
{ $mergeObjects: [
"$$this",
{ reportees: { $filter: { input: "$$prev", as: "e", cond: { $eq: [ "$$e.managerId", "$$this.empId" ] } } } }
] }
]
]
}
}
}
}
}
}
}
},
{
$addFields: { reportees: "$reportees.currentLevelEmployees" }
}
]).pretty()
Giải pháp trên sẽ hoạt động cho nhiều cấp độ. Kết quả đầu ra:
{
"_id" : "10",
"empId" : "10",
"managerId" : "15",
"reportees" : [
{
"empId" : "6",
"name" : "Employee6",
"managerId" : "10",
"level" : NumberLong(0),
"reportees" : [
{
"empId" : "1",
"name" : "Employee1",
"managerId" : "6",
"level" : NumberLong(1),
"reportees" : [ ]
},
{
"empId" : "2",
"name" : "Employee2",
"managerId" : "6",
"level" : NumberLong(1),
"reportees" : [ ]
}
]
},
{
"empId" : "8",
"name" : "Employee8",
"managerId" : "10",
"level" : NumberLong(0),
"reportees" : [
{
"empId" : "5",
"name" : "Employee5",
"managerId" : "8",
"level" : NumberLong(1),
"reportees" : [ ]
},
{
"empId" : "4",
"name" : "Employee4",
"managerId" : "8",
"level" : NumberLong(1),
"reportees" : [ ]
}
]
}
]
}