Не се вижда веднага, но е възможно. Това, което трябва да направите тук, е да комбинирате своя документ от най-високо ниво с масива от коментари, без да го дублирате. Ето един подход първо да обедините съдържанието като два масива в единичен масив, след което $unwind
за групиране на съдържанието:
db.collection.aggregate([
{ "$group": {
"_id": "$_id",
"author": {
"$addToSet": {
"id": "$_id",
"author": "$author",
"votes": "$votes"
}
},
"comments": { "$first": "$comments" }
}},
{ "$project": {
"combined": { "$setUnion": [ "$author", "$comments" ] }
}},
{ "$unwind": "$combined" },
{ "$group": {
"_id": "$combined.author",
"votes": { "$sum": "$combined.votes" }
}},
{ "$sort": { "votes": -1 } }
])
Което дава резултата:
{ "_id" : "Jesse", "votes" : 148 }
{ "_id" : "Mirek", "votes" : 135 }
{ "_id" : "Leszke", "votes" : 13 }
Дори при пропускане на първия $group
етап и създаване на комбиниран масив по различен начин:
db.collection.aggregate([
{ "$project": {
"combined": {
"$setUnion": [
{ "$map": {
"input": { "$literal": ["A"] },
"as": "el",
"in": {
"author": "$author",
"votes": "$votes"
}
}},
"$comments"
]
}
}},
{ "$unwind": "$combined" },
{ "$group": {
"_id": "$combined.author",
"votes": { "$sum": "$combined.votes" }
}},
{ "$sort": { "votes": -1 } }
])
Те използват оператори като $setUnion
и дори $map
които бяха въведени от MongoDB 2.6. Това го прави по-просто, но все още може да се направи в по-ранни версии без тези оператори, следвайки почти същите принципи:
db.collection.aggregate([
{ "$project": {
"author": 1,
"votes": 1,
"comments": 1,
"type": { "$const": ["A","B"] }
}},
{ "$unwind": "$type" },
{ "$unwind": "$comments" },
{ "$group": {
"_id": {
"$cond": [
{ "$eq": [ "$type", "A" ] },
{
"id": "$_id",
"author": "$author",
"votes": "$votes"
},
"$comments"
]
}
}},
{ "$group": {
"_id": "$_id.author",
"votes": { "$sum": "$_id.votes" }
}},
{ "$sort": { "votes": -1 } }
])
$const
е недокументиран, но присъства във всички версии на MongoDB, където присъства рамката за агрегиране (от 2.2). MongoDB 2.6 Представен $literal
което по същество се свързва със същия основен код. Използван е в два случая тук или за предоставяне на шаблонен елемент за масив, или за въвеждане на масив за разгъване, за да се осигури „двоичен избор“ между две действия.