Vous faites une erreur dès le début de votre pipeline d'agrégation
$project: {
"tasks" : 1
}
par lequel vous perdez toutes vos données. Donc, tout d'abord, vous devez le réserver en faisant :
$project: {
tasks: 1,
doc: {
title: "$title",
order: "$order",
description: "$description",
status: "$status"
}
}
Effectuez ensuite votre $unwind
s comme vous le faites dans votre question :
{$unwind: "$tasks"}, {$unwind: "$tasks.subTasks"}
Faites ensuite le tri. Vous devez faire le tri avec des clés composées, sinon le tri par tasks.subTasks.order
ne tiendra pas dès que vous triez par tasks.order
. Donc :
{$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}}
Et puis vient le plus dur. Vous devez $group
sauvegarder les résultats, et la première étape consiste à $push
sauvegarder les subTasks
, mais tout d'abord, encore une fois, vous devez conserver les attributs de la tâche :
$project: {
doc: 1,
task_id: "$tasks._id",
tasks_doc: {
title: "$tasks.title",
description: "$tasks.description",
order: "$tasks.order",
status: "$tasks.status"
},
subTasks: "$tasks.subTasks"
}
...collecter les subTasks
:
$group: {
_id: {
_id: "$_id",
task_id: "$task_id",
doc: "$doc",
task_doc: "$tasks_doc"
},
subTasks: {
$push: "$subTasks"
}
}
Et pareil pour les tasks
. Faites attention que pendant le $group
ing vous devez également projeter en arrière le task_doc
attributs :
$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"
}
}
}
Et puis projetez en arrière la racine doc
attributs :
$project: {
_id: "$_id._id",
title: "$_id.doc.title",
description: "$_id.doc.description",
order: "$_id.doc.order",
status: "$_id.doc.status",
tasks: 1
}
C'est fondamentalement ça. Voici le pipeline d'agrégation brut complet, afin que vous puissiez tester et voir si vous obtenez le résultat souhaité :
[
{$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}}
]
MISE À JOUR
Si un champ tableau est vide ou n'existe pas (est null
) le $unwind
l'opération sur ce champ renverra un résultat vide
. La solution à cette situation consiste initialement à configurer le null
/champ vide à un certain zero
valeur, par ex. "<empty-array>"
. Notez que vous devez faire ceci $project
ion pour chaque tableau, avant son $unwind
.
Jetez un oeil à cette réponse
sur la façon d'utiliser le $ifNull
opérateur. Vérifiez également le $size
opérateur ici
.
Après avoir traité cette partie, vous devez $group
sauvegarder les résultats, et cela peut être réalisé en utilisant le $cond
opérateur
, pour vérifier par rapport à "<empty-array>"
valeur