MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Calcola la media dei campi nei documenti/array incorporati

Il framework di aggregazione in MongoDB 3.4 e versioni successive offre il $reduce operatore che calcola in modo efficiente il totale senza la necessità di tubazioni aggiuntive. Prendi in considerazione l'utilizzo come espressione per restituire le valutazioni totali e ottenere il numero di valutazioni utilizzando $size . Insieme a $addFields , la media può quindi essere calcolata utilizzando l'operatore aritmetico $divide come nella formula 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
                        ]
                    }
                ]
            }
        }
    }           
])

Risultato campione

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

Con le versioni precedenti, dovresti prima applicare il $unwind operatore sui ratings campo array prima come passaggio iniziale della pipeline di aggregazione. Questo decostruirà le ratings campo matrice dai documenti di input per produrre un documento per ogni elemento. Ogni documento di output sostituisce l'array con un valore di elemento.

La seconda fase della pipeline sarebbe il $group operatore che raggruppa i documenti di input in base a _id e title chiavi dell'espressione dell'identificatore e applica il $avg desiderato accumulatore per ciascun gruppo che calcola la media. C'è un altro operatore di accumulatori $push che preserva il campo dell'array delle valutazioni originali restituendo un array di tutti i valori risultanti dall'applicazione di un'espressione a ciascun documento nel gruppo precedente.

Il passaggio finale della pipeline è il $project operatore che quindi rimodella ogni documento nello stream, ad esempio aggiungendo il nuovo campo ratings_average .

Quindi, se ad esempio hai un documento campione nella tua collezione (come da sopra e così sotto):

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

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

Per calcolare la media dell'array di valutazioni e proiettare il valore in un altro campo ratings_average , puoi quindi applicare la seguente pipeline di aggregazione:

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

Risultato :

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