Inte direkt synligt men möjligt. Vad du behöver göra här är att kombinera ditt dokument på högsta nivå med mängden kommentarer utan att duplicera det. Här är ett tillvägagångssätt för att först sammanfoga innehållet som två arrayer till en singulär array, sedan $unwind
för att gruppera innehållet:
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 } }
])
Vilket ger utdata:
{ "_id" : "Jesse", "votes" : 148 }
{ "_id" : "Mirek", "votes" : 135 }
{ "_id" : "Leszke", "votes" : 13 }
Även som att hoppa över den första $group
steg och gör en kombinerad array på ett annat sätt:
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 } }
])
De använder operatorer som $setUnion
och till och med $map
som introducerades från och med MongoDB 2.6. Detta gör det enklare, men det kan fortfarande göras i tidigare versioner som saknar dessa operatörer, enligt ungefär samma principer:
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
är odokumenterad men finns i alla versioner av MongoDB där aggregeringsramverket finns (från 2.2). MongoDB 2.6 introducerade $literal
som i huvudsak länkar till samma underliggande kod. Det har använts i två fall här för att antingen tillhandahålla ett mallelement för en array, eller som att introducera en array för att varva ner för att ge ett "binärt val" mellan två åtgärder.