Search code examples
mongodbgroup-byaverageaggregation-frameworkrank

MongoDB Get average of group considering rank of document


I have documents getting in order like:

{ 
   "_id": "abcde1",
   "value" : 300
},
{ 
   "_id": "abcde2",
   "value" : 200
},
{ 
   "_id": "abcde3",
   "value" : 400
},
{ 
   "_id": "abcde4",
   "value" : 500
},
{ 
   "_id": "abcde5",
   "value" : 600
}

i.e, I want average of "_id" of first 2, first 4 and all 5 documents matching like in single query:

{
    "value_2" : 250,   // Average of first 2 documents
    "value_4" : 350,    // Average of first four documents
    "value_5" : 400     // Average of all 5 documents
}

Is it possible to Group documents based on rank of document.

I can do 3 results in 3 separate queries. Is it possible in single query?


Solution

  • You could try running the following pipeline:

    db.collection.aggregate([
        // previous pipeline here
        {
            "$group": {
                "_id": null,
                "values": { "$push": "$value" }                
            }
        },
        { "$unwind": { "path": "$values", "includeArrayIndex": "rank"  } },
        {
            "$group": {
                "_id": null,
                "value_2_sum": {
                    "$sum": { 
                        "$cond": [
                            { "$lt": ["$rank", 2] },
                            "$values",
                            0
                        ]
                    }
                },
                "value_2_count": {
                    "$sum": { 
                        "$cond": [
                            { "$lt": ["$rank", 2] },
                            1,
                            0
                        ]
                    }
                },
                "value_4_sum": {
                    "$sum": { 
                        "$cond": [
                            { "$lt": ["$rank", 4] },
                            "$values",
                            0
                        ]
                    }
                },
                "value_4_count": {
                    "$sum": { 
                        "$cond": [
                            { "$lt": ["$rank", 4] },
                            1,
                            0
                        ]
                    }
                },
                "value_5": { "$avg": "$values" }
            }
        },
        {
            "$project": {
                "value_2" : { "$divide": ["$value_2_sum", "$value_2_count"] },   // Average of first 2 documents
                "value_4" : { "$divide": ["$value_4_sum", "$value_4_count"] },    // Average of first four documents
                "value_5" : 1
            }
        }
    ])