Aggregeringsrammen i MongoDB 3.4 og nyere tilbyder $reduce
operatør, som effektivt beregner totalen uden behov for ekstra rørledninger. Overvej at bruge det som et udtryk for at returnere de samlede vurderinger og få antallet af vurderinger ved hjælp af $size
. Sammen med $addFields
, kan gennemsnittet således beregnes ved hjælp af den aritmetiske operator $divide
som i formlen 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
]
}
]
}
}
}
])
Eksempeloutput
{
"_id" : ObjectId("58ab48556da32ab5198623f4"),
"title" : "The Hobbit",
"ratings" : [
{
"title" : "best book ever",
"rating" : 5.0
},
{
"title" : "good book",
"rating" : 3.5
}
],
"rating_average" : 4.25
}
Med ældre versioner skal du først anvende $unwind
operatør på ratings
matrixfelt først som dit indledende aggregeringspipelinetrin. Dette vil dekonstruere ratings
matrixfelt fra inputdokumenterne for at udskrive et dokument for hvert element. Hvert outputdokument erstatter arrayet med en elementværdi.
Det andet pipelinetrin ville være $group
operatør, som grupperer inputdokumenter efter _id
og title
nøgleidentifikatorudtryk og anvender den ønskede $avg
akkumulatorudtryk til hver gruppe, der beregner gennemsnittet. Der er en anden akkumulatoroperator $push
der bevarer det oprindelige bedømmelsesmatrixfelt ved at returnere en matrix af alle værdier, der er resultatet af at anvende et udtryk på hvert dokument i ovenstående gruppe.
Det sidste pipeline-trin er $project
operatør, som derefter omformer hvert dokument i strømmen, f.eks. ved at tilføje det nye felt ratings_average
.
Så hvis du for eksempel har et eksempeldokument i din samling (som ovenfra og så nedenfor):
db.collection.insert({
"title": "The Hobbit",
"ratings": [
{
"title": "best book ever",
"rating": 5
},
{
"title": "good book",
"rating": 3.5
}
]
})
For at beregne bedømmelsesmatrixgennemsnittet og projicere værdien i et andet felt ratings_average
, kan du derefter anvende følgende aggregeringspipeline:
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
}
}
])
Resultat :
/* 1 */
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}