Děláte chybu hned od začátku svého agregačního kanálu
$project: {
"tasks" : 1
}
čímž ztratíte všechna svá data. Takže nejprve si to musíte zarezervovat:
$project: {
tasks: 1,
doc: {
title: "$title",
order: "$order",
description: "$description",
status: "$status"
}
}
Poté proveďte $unwind
stejně jako ve své otázce:
{$unwind: "$tasks"}, {$unwind: "$tasks.subTasks"}
Pak proveďte třídění. Musíte provést řazení pomocí složených klíčů, jinak řazení podle tasks.subTasks.order
nebude držet, jakmile seřadíte podle tasks.order
. Takže:
{$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}}
A pak přijde ta těžší část. Musíte $group
zpět výsledky a prvním krokem je $push
zpět subTasks
, ale v první řadě je opět potřeba zachovat atributy úkolu:
$project: {
doc: 1,
task_id: "$tasks._id",
tasks_doc: {
title: "$tasks.title",
description: "$tasks.description",
order: "$tasks.order",
status: "$tasks.status"
},
subTasks: "$tasks.subTasks"
}
...sbírat subTasks
:
$group: {
_id: {
_id: "$_id",
task_id: "$task_id",
doc: "$doc",
task_doc: "$tasks_doc"
},
subTasks: {
$push: "$subTasks"
}
}
A to samé pro tasks
. Věnujte pozornost tomu, že během $group
je také potřeba promítnout zpět task_doc
atributy:
$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"
}
}
}
A pak promítněte zpět kořenový doc
atributy:
$project: {
_id: "$_id._id",
title: "$_id.doc.title",
description: "$_id.doc.description",
order: "$_id.doc.order",
status: "$_id.doc.status",
tasks: 1
}
To je v podstatě vše. Zde je úplný nezpracovaný agregační kanál, takže můžete otestovat a zjistit, zda získáte požadovaný výsledek:
[
{$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}}
]
AKTUALIZACE
Pokud je pole pole prázdné nebo neexistuje (je null
) $unwind
operace na tomto poli vrátí prázdný výsledek
. Řešením této situace je zpočátku nastavení null
/prázdné pole na nějakou zero
hodnotu, např. "<empty-array>"
. Všimněte si, že musíte provést tento $project
ion pro každé pole, před jeho $unwind
.
Podívejte se na tuto odpověď
o tom, jak používat $ifNull
operátor. Podívejte se také na $size
operátor zde
.
Poté, co se vypořádáte s touto částí, musíte $group
zpět výsledky a toho lze dosáhnout pomocí $cond
operátor
, pro kontrolu proti "<empty-array>"
hodnotu