sql >> Databasteknik >  >> NoSQL >> MongoDB

Beräkna medelvärdet av fält i inbäddade dokument/array

Aggregeringsramverket i MongoDB 3.4 och nyare erbjuder $reduce operatör som effektivt beräknar totalsumman utan behov av extra rörledningar. Överväg att använda det som ett uttryck för att returnera de totala betygen och få antalet betyg med $size . Tillsammans med $addFields , medelvärdet kan alltså beräknas med den aritmetiska operatorn $divide som i formeln 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
                        ]
                    }
                ]
            }
        }
    }           
])

Exempel på utdata

{
    "_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 måste du först tillämpa $unwind operatorn på ratings arrayfältet först som ditt första aggregeringspipelinesteg. Detta kommer att dekonstruera ratings matrisfält från inmatningsdokumenten för att mata ut ett dokument för varje element. Varje utdatadokument ersätter arrayen med ett elementvärde.

Det andra pipelinesteget skulle vara $group operator som grupperar inmatade dokument efter _id och title keys identifier uttryck och tillämpar önskad $avg ackumulatoruttryck till varje grupp som beräknar medelvärdet. Det finns en annan ackumulatoroperatör $push som bevarar det ursprungliga klassificeringsfältet genom att returnera en matris med alla värden som är resultatet av att ett uttryck tillämpas på varje dokument i ovanstående grupp.

Det sista pipelinesteget är $project operator som sedan omformar varje dokument i flödet, till exempel genom att lägga till det nya fältet ratings_average .

Så, om du till exempel har ett exempeldokument i din samling (som från ovan och så nedan):

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

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

För att beräkna genomsnittet för betygsmatrisen och projicera värdet i ett annat fält ratings_average , kan du sedan använda följande 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
}


  1. Integrering av ClusterControl med SNMP:Del två

  2. pymongo:MongoClient eller Connection

  3. Det gick inte att starta redis.service:Enheten redis-server.service är maskerad

  4. Ställ in Mongo Timeout i Spring Boot