Правите грешка още от самото начало на вашия конвейер за агрегиране
$project: {
"tasks" : 1
}
с което губите всичките си данни. Така че първо трябва да го резервирате, като направите:
$project: {
tasks: 1,
doc: {
title: "$title",
order: "$order",
description: "$description",
status: "$status"
}
}
След това изпълнете своя $unwind
както правите във въпроса си:
{$unwind: "$tasks"}, {$unwind: "$tasks.subTasks"}
След това направете сортирането. Трябва да направите сортирането със съставни ключове, в противен случай подреждането по tasks.subTasks.order
няма да се задържи веднага щом сортирате по tasks.order
. И така:
{$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}}
И тогава идва трудната част. Трябва да $group
върнете резултатите и първата стъпка е $push
обратно на subTasks
, но преди всичко отново трябва да запазите атрибутите на задачата:
$project: {
doc: 1,
task_id: "$tasks._id",
tasks_doc: {
title: "$tasks.title",
description: "$tasks.description",
order: "$tasks.order",
status: "$tasks.status"
},
subTasks: "$tasks.subTasks"
}
...съберете subTasks
:
$group: {
_id: {
_id: "$_id",
task_id: "$task_id",
doc: "$doc",
task_doc: "$tasks_doc"
},
subTasks: {
$push: "$subTasks"
}
}
И същото за tasks
. Обърнете внимание, че по време на $group
ing също трябва да проектирате обратно task_doc
атрибути:
$group: {
_id: {
_id: "$_id._id",
doc: "$_id.doc"
},
tasks: {
$push: {
_id: "$_id.task_id",
title: "$_id.task_doc.title",
description: "$_id.task_doc.description",
order: "$_id.task_doc.order",
status: "$_id.task_doc.status"
subTasks: "$subTasks"
}
}
}
И след това проектирайте обратно основния doc
атрибути:
$project: {
_id: "$_id._id",
title: "$_id.doc.title",
description: "$_id.doc.description",
order: "$_id.doc.order",
status: "$_id.doc.status",
tasks: 1
}
Това е в общи линии. Ето пълния тръбопровод за необработено агрегиране, така че можете да тествате и да видите дали получавате желания резултат:
[
{$match: {_id: ObjectId("554a13d4b692088a38f01f3b")}},
{$project: {tasks: 1, doc: {title: "$title", order: "$order", description: "$description", status: "$status"}}},
{$unwind: "$tasks"},
{$unwind: "$tasks.subTasks"},
{$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}},
{$project: {doc: 1, task_id: "$tasks._id", tasks_doc: {title: "$tasks.title", description: "$tasks.description", order: "$tasks.order", status: "$tasks.status"}, subTasks: "$tasks.subTasks"}},
{$group: {_id: {_id: "$_id", task_id: "$task_id", doc: "$doc", task_doc: "$tasks_doc"}, subTasks: {$push: "$subTasks"}}},
{$group: {_id: {_id: "$_id._id", doc: "$_id.doc"}, tasks: {$push: {_id: "$_id.task_id", title: "$_id.task_doc.title", description: "$_id.task_doc.description", order: "$_id.task_doc.order", status: "$_id.task_doc.status", subTasks: "$subTasks"}}}},
{$project: {_id: "$_id._id", title: "$_id.doc.title", description: "$_id.doc.description", order: "$_id.doc.order", status: "$_id.doc.status", tasks: 1}}
]
АКТУАЛИЗАЦИЯ
Ако поле за масив е празно или не съществува (е null
) $unwind
операция в това поле ще върне празен резултат
. Решението на тази ситуация е първоначалната настройка на null
/празно поле до някаква zero
стойност, напр. "<empty-array>"
. Имайте предвид, че трябва да направите този $project
ion за всеки масив, преди неговия $unwind
.
Разгледайте този отговор
за това как да използвате $ifNull
оператор. Вижте и $size
оператор тук
.
След като се справите с тази част, трябва да $group
върнете резултатите и това може да се постигне с помощта на $cond
оператор
, за да проверите спрямо "<empty-array>"
стойност