Você está cometendo um erro desde o início do pipeline de agregação
$project: {
"tasks" : 1
}
pelo qual você perde todos os seus dados. Então, antes de tudo, você precisa reservá-lo fazendo:
$project: {
tasks: 1,
doc: {
title: "$title",
order: "$order",
description: "$description",
status: "$status"
}
}
Depois execute seu
$unwind
s como você faz na sua pergunta:{$unwind: "$tasks"}, {$unwind: "$tasks.subTasks"}
Em seguida, faça a triagem. Você precisa fazer a ordenação com chaves compostas, caso contrário a ordenação por
tasks.subTasks.order
não será retido assim que você classificar por tasks.order
. Então:{$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}}
E então vem a parte difícil. Você precisa
$group
de volta os resultados, e o primeiro passo é $push
de volta as subTasks
, mas antes de tudo, novamente você precisa preservar os atributos da tarefa:$project: {
doc: 1,
task_id: "$tasks._id",
tasks_doc: {
title: "$tasks.title",
description: "$tasks.description",
order: "$tasks.order",
status: "$tasks.status"
},
subTasks: "$tasks.subTasks"
}
...coletar
subTasks
:$group: {
_id: {
_id: "$_id",
task_id: "$task_id",
doc: "$doc",
task_doc: "$tasks_doc"
},
subTasks: {
$push: "$subTasks"
}
}
E o mesmo para as
tasks
. Preste atenção que durante o $group
você também precisa projetar de volta o task_doc
atributos:$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"
}
}
}
E então projete de volta a raiz
doc
atributos:$project: {
_id: "$_id._id",
title: "$_id.doc.title",
description: "$_id.doc.description",
order: "$_id.doc.order",
status: "$_id.doc.status",
tasks: 1
}
É basicamente isso. Aqui está o pipeline completo de agregação bruta, para que você possa testar e ver se obtém o resultado desejado:
[
{$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}}
]
ATUALIZAÇÃO
Se um campo de matriz estiver vazio ou não existir (é
null
) o $unwind
a operação nesse campo retornará um resultado vazio
. A solução para esta situação é inicialmente configurar o null
/empty campo para algum zero
valor, por exemplo "<empty-array>"
. Observe que você precisa fazer isso $project
ion para cada array, antes de seu $unwind
. Dê uma olhada esta resposta sobre como usar o
$ifNull
operador. Confira também o $size
operador aqui
. Depois de lidar com esta parte, você precisa
$group
os resultados, e isso pode ser feito usando o $cond
operador
, para verificar o "<empty-array>"
valor