Mongodb - getting highest result from nested element

I need to get user ratings from multiple points. Here's a sample mongo data:

{
    _id: "peter",
    name: "Peter Griffin",
    scores : [
        {
           event: "Peter Copter race",
           score: 100,
        },
        {
           event: "World domination",
           score: 0,
        },
        {
           event: "Listening",
           score: 10,
        }
    ]
},
{
   _id: "stewie",
   name: "Stuart Griffin",
   scores : [
       {
           event: "Peter Copter race",
           score: 0,
       },
       {
           event: "World domination",
           score: 1000,
       },
       {
           event: "Listening",
           score: 100,
       }
   ]
}

      

I want to get the top score for each user by returning s'thing like

[{"_id": "peter", "top_score" : 100}, {"_id": "stewie", "top_score" : 1000}]

      

Here's what I have so far:

   db.famguyMongo.find({ "scores": { $exists: true } }).forEach(function(famMember) {
    var newScore = 0
    famMember.scores.forEach(function(getScore) {
        newScore = {$max: getScore.score}
    });
    print(newScore )
    newScore = 0
});

      

As you can see, I try to check var every time. I also tried this:

db.famguyMongo.find({ "scores": { $exists: true } }).forEach(function(famMember) {
    var newScore = 0
    famMember.scores.forEach(function(getScore) {
        newScore = { $cond: { $gte: [getScore.score, newScore] } getScore.score, 0 }
    });
    print(newScore)
    newScore = 0
});

      

+3


source to share


2 answers


You can try MongoDB aggregation framework to calculate the maximum score for each user. In your aggregation pipeline, the first step is to deconstruct the array field from the input documents, using document output for each element, which can then be grouped later along the pipeline. Each output replaces the array with the element's value. The next stage of the pipeline will be the operator , where you can calculate the maximum result using the field . The last step is an operation where you can modify each document in the stream to map the required fields to the appropriate format: scores

$unwind

$group

$max

scores.score

$project

db.collection.aggregate([
    {
        "$unwind": "$scores"
    },
    {
        "$group": {
            "_id": "$_id",
            "highest_score": { "$max": "$scores.score" }
        }
    },
    {
        "$project": {
            "_id": 0,
            "name": "$_id",
            "highest_score": 1
        }
    }
]);

      



Result

/* 0 */
{
    "result" : [ 
        {
            "highest_score" : 1000,
            "name" : "stewie"
        }, 
        {
            "highest_score" : 100,
            "name" : "peter"
        }
    ],
    "ok" : 1
}

      

+3


source


I would recommend using chridam's answer , but if you want to use a JavaScript alternative,

var objScores = {}; //Instantiate object
db.test.find({ "scores": { $exists: true } }).forEach(function(famMember) {
    var newScore = 0;
    objScores[famMember._id] = 0; //Set default for each person as score 0
    famMember.scores.forEach(function(getScore) { //loop through persons score
        if( getScore.score > objScores[famMember._id] ) {
            objScores[famMember._id] = getScore.score; //Record the highest score
        }
    });
});
print( objScores ); //print output

      



And the output will be:

{
    "peter" : 100,
    "stewie" : 1000
}

      

+1


source







All Articles