MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Calculer la moyenne des champs dans les documents/tableaux intégrés

Le framework d'agrégation de MongoDB 3.4 et plus récent offre le $reduce opérateur qui calcule efficacement le total sans avoir besoin de pipelines supplémentaires. Envisagez de l'utiliser comme expression pour renvoyer les notes totales et obtenir le nombre de notes à l'aide de $size . Avec $addFields , la moyenne peut ainsi être calculée à l'aide de l'opérateur arithmétique $divide comme dans la 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
                        ]
                    }
                ]
            }
        }
    }           
])

Exemple de sortie

{
    "_id" : ObjectId("58ab48556da32ab5198623f4"),
    "title" : "The Hobbit",
    "ratings" : [ 
        {
            "title" : "best book ever",
            "rating" : 5.0
        }, 
        {
            "title" : "good book",
            "rating" : 3.5
        }
    ],
    "rating_average" : 4.25
}

Avec les anciennes versions, vous devez d'abord appliquer le $unwind opérateur sur les ratings champ de tableau en premier comme étape initiale du pipeline d'agrégation. Cela déconstruira les ratings champ de tableau des documents d'entrée pour produire un document pour chaque élément. Chaque document de sortie remplace le tableau par une valeur d'élément.

La deuxième étape du pipeline serait le $group opérateur qui regroupe les documents d'entrée par le _id et title l'expression d'identifiant des clés et applique le $avg souhaité expression d'accumulateur à chaque groupe qui calcule la moyenne. Il existe un autre opérateur d'accumulateur $push qui préserve le champ de tableau des évaluations d'origine en renvoyant un tableau de toutes les valeurs résultant de l'application d'une expression à chaque document du groupe ci-dessus.

La dernière étape du pipeline est le $project opérateur qui remodèle ensuite chaque document dans le flux, par exemple en ajoutant le nouveau champ ratings_average .

Donc, si par exemple vous avez un exemple de document dans votre collection (comme ci-dessus et donc ci-dessous) :

db.collection.insert({
    "title": "The Hobbit",

    "ratings": [
        {
            "title": "best book ever",
            "rating": 5
        },
        {
            "title": "good book",
            "rating": 3.5
        }
    ]
})

Pour calculer la moyenne du tableau des notes et projeter la valeur dans un autre champ ratings_average , vous pouvez ensuite appliquer le pipeline d'agrégation suivant :

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
        }
    }
])

Résultat :

/* 1 */
{
    "result" : [ 
        {
            "ratings" : [ 
                {
                    "title" : "best book ever",
                    "rating" : 5
                }, 
                {
                    "title" : "good book",
                    "rating" : 3.5
                }
            ],
            "ratings_average" : 4.25,
            "title" : "The Hobbit"
        }
    ],
    "ok" : 1
}