O seguinte pipeline deve funcionar para você:
var pipeline = [
{
"$project": {
"title": 1, "body": 1,
"post_id": { "$ifNull": [ "$_post", "$_id" ] }
}
},
{
"$group": {
"_id": "$post_id",
"title": { "$first": "$title" },
"body": { "$first": "$body" },
"comments": {
"$push": {
"_id": "$_id",
"_post": "$post_id",
"body": "$body"
}
}
}
},
{
"$project": {
"title": 1, "body": 1,
"comments": {
"$setDifference": [
{
"$map": {
"input": "$comments",
"as": "el",
"in": {
"$cond": [
{ "$ne": [ "$$el._id", "$$el._post" ] },
"$$el",
false
]
}
}
},
[false]
]
}
}
}
];
Post.aggregate(pipeline, function (err, result) {
if (err) { /* handle error */ };
console.log(result);
});
O pipeline é estruturado de forma que sua primeira etapa, o
$project
estágio do operador, é projetar o campo post_id
para ser usado como o grupo por chave no próximo estágio do pipeline. Como seu esquema é hierárquico, você precisaria desse campo para documentos pai/raiz. O $ifNull
operador atuará como operador de coalescência e retornará o valor de substituição caso o campo não exista nos documentos. A próxima etapa do pipeline, o
$grupo
O estágio de pipeline tenta agrupar os dados para processá-los. O $group
operador de pipeline é semelhante à cláusula GROUP BY do SQL. Em SQL, não podemos usar GROUP BY a menos que usemos qualquer uma das funções de agregação. Da mesma forma, temos que usar uma função de agregação no MongoDB também. Nesse caso, você precisa do $push
operador para criar a matriz de comentários. Os outros campos são então acumulados usando o $primeiro
operador. A etapa final envolve ajustar a matriz de comentários para que você remova o documento com os detalhes da postagem, que definitivamente não é um tipo de comentário. Isso é possível por meio do
$setDifference
e $map
operadores. O $map
Essencialmente, o operador cria um novo campo de matriz que contém valores como resultado da lógica avaliada em uma subexpressão para cada elemento de uma matriz. O $setDifference
operador então retorna um conjunto com elementos que aparecem no primeiro conjunto, mas não no segundo conjunto; isto é, realiza um complemento relativo do segundo conjunto em relação ao primeiro. Nesse caso, ele retornará os comentários
finais array que possui elementos não relacionados aos documentos pai através do _id
propriedade.