Reputation: 711
I need to get a users top score from a variety of score. Here's a sample mongo dataset:
{
_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, returning s'thing like
[{"_id": "peter", "top_score" : 100}, {"_id": "stewie", "top_score" : 1000}]
Here's what I've got 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'm trying to set an var to be checked each time.. I've 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
});
Upvotes: 3
Views: 346
Reputation: 11375
I'd recommended using chridam's answer, but if you wanted 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 output would be;
{
"peter" : 100,
"stewie" : 1000
}
Upvotes: 1
Reputation: 103445
You could try MongoDB's aggregation framework to calculate the maximum score per user. In your aggregation pipeline, the first step is to deconstruct the scores
array field from the input documents using the $unwind
operator to output a document for each element that you can then aggregate on later down the pipeline. Each output document replaces the array with an element value. The next pipeline stage will be the $group
operator where you can then calculate the highest score using the $max
aggregation operator on the scores.score
field. The final step is the $project
operation where you can reshape each document in the stream to display the required fields in the appropriate format:
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
}
Upvotes: 3