Следният конвейер трябва да работи за вас:
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);
});
Тръбопроводът е структуриран по такъв начин, че първата ви стъпка, $project
оператор етап, е да се проектира полето post_id
да се използва като група по ключ в следващия етап на конвейера. Тъй като вашата схема е йерархична, ще ви е необходимо това поле за родителски/главни документи. $ifNullкод>
ще действа като оператор за обединяване и ще върне заместващата стойност, ако полето не съществува в документите.
Следващата стъпка на конвейера, $група
етапът на тръбопровод се опитва да групира данните, за да ги обработи. $groupкод>
конвейерният оператор е подобен на клаузата GROUP BY на SQL. В SQL не можем да използваме GROUP BY, освен ако не използваме някоя от функциите за агрегиране. По същия начин трябва да използваме функция за агрегиране и в MongoDB. В този случай имате нужда от $push
оператор за създаване на масива с коментари. След това другите полета се натрупват с помощта на $first
оператор.
Последната стъпка включва филтриране на масива с коментари, така че да премахнете документа с подробности за публикацията, който определено не е от тип коментар. Това става възможно чрез $setDifference
и $mapкод>
оператори. $mapкод>
операторът по същество създава ново поле за масив, което съдържа стойности в резултат на изчислената логика в подизраз към всеки елемент от масив. $setDifferenceкод>
след това операторът връща набор с елементи, които се появяват в първия набор, но не и във втория набор; т.е. извършва относително допълнение на втория набор спрямо първия. В този случай той ще върне окончателните коментари
масив, който има елементи, които не са свързани с родителските документи чрез _id
собственост.