Het aggregatieraamwerk in MongoDB 3.4 en nieuwer biedt de $reduce
operator die efficiënt het totaal berekent zonder dat er extra leidingen nodig zijn. Overweeg het te gebruiken als een uitdrukking om het totale aantal beoordelingen te retourneren en het aantal beoordelingen te krijgen met behulp van $size
. Samen met $addFields
, kan het gemiddelde dus worden berekend met behulp van de rekenkundige operator $divide
zoals in de formule average = total ratings/number of ratings
:
db.collection.aggregate([
{
"$addFields": {
"rating_average": {
"$divide": [
{ // expression returns total
"$reduce": {
"input": "$ratings",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.rating"] }
}
},
{ // expression returns ratings count
"$cond": [
{ "$ne": [ { "$size": "$ratings" }, 0 ] },
{ "$size": "$ratings" },
1
]
}
]
}
}
}
])
Voorbeelduitvoer
{
"_id" : ObjectId("58ab48556da32ab5198623f4"),
"title" : "The Hobbit",
"ratings" : [
{
"title" : "best book ever",
"rating" : 5.0
},
{
"title" : "good book",
"rating" : 3.5
}
],
"rating_average" : 4.25
}
Bij oudere versies moet u eerst de $unwind
. toepassen operator op de ratings
array-veld eerst als uw eerste aggregatiepijplijnstap. Dit zal de ratings
deconstrueren matrixveld uit de invoerdocumenten om een document voor elk element uit te voeren. Elk uitvoerdocument vervangt de array door een elementwaarde.
De tweede pijplijnfase is de $group
operator die invoerdocumenten groepeert op de _id
en title
sleutels identifier-expressie en past de gewenste $avg
. toe accumulatoruitdrukking toe aan elke groep die het gemiddelde berekent. Er is een andere accumulator-operator $push
dat het oorspronkelijke veld voor de classificatiearray behoudt door een array te retourneren van alle waarden die het resultaat zijn van het toepassen van een uitdrukking op elk document in de bovenstaande groep.
De laatste pijplijnstap is het $project
operator die vervolgens elk document in de stream hervormt, bijvoorbeeld door het nieuwe veld ratings_average
toe te voegen .
Dus als u bijvoorbeeld een voorbeelddocument in uw collectie heeft (zoals van boven en zo onder):
db.collection.insert({
"title": "The Hobbit",
"ratings": [
{
"title": "best book ever",
"rating": 5
},
{
"title": "good book",
"rating": 3.5
}
]
})
Om het gemiddelde van de beoordelingsreeks te berekenen en de waarde in een ander veld te projecteren ratings_average
, kunt u vervolgens de volgende aggregatiepijplijn toepassen:
db.collection.aggregate([
{
"$unwind": "$ratings"
},
{
"$group": {
"_id": {
"_id": "$_id",
"title": "$title"
},
"ratings":{
"$push": "$ratings"
},
"ratings_average": {
"$avg": "$ratings.rating"
}
}
},
{
"$project": {
"_id": 0,
"title": "$_id.title",
"ratings_average": 1,
"ratings": 1
}
}
])
Resultaat :
/* 1 */
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}