La seguente pipeline dovrebbe funzionare per te:
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);
});
La pipeline è strutturata in modo tale che il tuo primo passo, il $project
fase operatore, è quello di proiettare il campo post_id
da utilizzare come gruppo per chiave nella fase successiva della pipeline. Poiché il tuo schema è gerarchico, avresti bisogno di questo campo per i documenti padre/root. Il $ifNull
l'operatore fungerà da operatore coalescente e restituirà il valore sostitutivo se il campo non esiste nei documenti.
Il passaggio successivo della pipeline, il $group
la fase della pipeline tenta di raggruppare i dati per elaborarli. Il $group
l'operatore della pipeline è simile alla clausola GROUP BY di SQL. In SQL, non possiamo utilizzare GROUP BY a meno che non utilizziamo una delle funzioni di aggregazione. Allo stesso modo, dobbiamo usare anche una funzione di aggregazione in MongoDB. In questo caso è necessario il $push
operatore per creare la matrice dei commenti. Gli altri campi vengono quindi accumulati utilizzando $first
operatore.
Il passaggio finale prevede l'adattamento dell'array dei commenti in modo da rimuovere il documento con i dettagli del post, che sicuramente non è di un tipo di commento. Ciò è possibile tramite $setDifference
e $map
operatori. Il $map
in sostanza, l'operatore crea un nuovo campo di matrice che contiene i valori come risultato della logica valutata in una sottoespressione per ciascun elemento di una matrice. Il $setDifference
l'operatore restituisce quindi un insieme con elementi che appaiono nel primo insieme ma non nel secondo insieme; cioè esegue un complemento relativo del secondo insieme rispetto al primo. In questo caso restituirà i comments
finali array che ha elementi non correlati ai documenti principali tramite _id
proprietà.