Die aggregation framework in MongoDB 3.4 und höher bietet die $reduce
Betreiber, die effizient die Summe für zusätzliche Pipelines ohne die Notwendigkeit berechnet. Erwägen Sie, es als Ausdruck zu verwenden, um die Gesamtbewertungen zurückzugeben und die Anzahl der Bewertungen unter Verwendung von $size
zu erhalten. Zusammen mit $addFields
kann die durchschnittliche damit den arithmetischen Operator $divide
wie in der Formel average = total ratings/number of ratings
berechnet werden:
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
]
}
]
}
}
}
])
Beispielausgabe
{
"_id" : ObjectId("58ab48556da32ab5198623f4"),
"title" : "The Hobbit",
"ratings" : [
{
"title" : "best book ever",
"rating" : 5.0
},
{
"title" : "good book",
"rating" : 3.5
}
],
"rating_average" : 4.25
}
Bei älteren Versionen Sie müssen zuerst den Operator $unwind
auf der Anwendung anwenden ratings
Array Feld zuerst als Ihre erste Aggregation Pipeline-Schritt. Dies dekonstruiert das Arrayfeld ratings
aus den Eingabedokumenten, um ein Dokument für jedes Element auszugeben. Jedes Ausgabedokument ersetzt das Array durch einen Elementwert.
Die zweite Pipeline-Stufe würde die $group
Operator die Dokumente Gruppen Eingabe durch den _id
und title
Ausdruck Schlüssel-Kennung und jeder Gruppe die gewünschte $avg
Akkumulator Ausdruck gilt, der den Mittelwert berechnet. Es gibt einen weiteren Akkumulatoroperator, $push
, der das Arrayfeld der ursprünglichen Bewertungen beibehält, indem ein Array aller Werte zurückgegeben wird, die sich aus der Anwendung eines Ausdrucks auf jedes Dokument in der obigen Gruppe ergeben. Der letzte Pipeline-Schritt ist der $project
-Operator, der dann jedes Dokument im Stream umformt, z. B. durch Hinzufügen des neuen Felds ratings_average
.
Also, wenn Sie zum Beispiel ein Beispieldokument in Ihrer Sammlung (von oben und so weiter unten):
db.collection.insert({
"title": "The Hobbit",
"ratings": [
{
"title": "best book ever",
"rating": 5
},
{
"title": "good book",
"rating": 3.5
}
]
})
Um die Bewertungen Array Durchschnitt zu berechnen und den Wert in einem anderen Feld Projizieren ratings_average
, können Sie dann gilt die folgende Aggregations Pipeline:
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
}
}
])
Ergebnis:
/* 1 */
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}
Danke, chridam :) – retrobitguy
@retrobitguy Keine Sorgen :-) – chridam
Das war sehr hilfreich und klar! Danke vielmals! – retrobitguy