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
});
source to share
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
}
source to share
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
}
source to share