30

I am using MongoDB , MongooseJS and Nodejs.

I have a Collection ( called Member ) with the following Fields -

Country_id , Member_id , Name, Score

I want to write a query which returns the Member with the max Score where Country id = 10

I couldnt find suitable documentation for this in MongooseJS.

I found this at StackOVerflow ( this is MongoDB code )

Model.findOne({ field1 : 1 }).sort(last_mod, 1).run( function(err, doc) {
     var max = doc.last_mod;
});

But how do I translate the same to MongooseJS ?

Community
  • 1
  • 1
geeky_monster
  • 8,672
  • 18
  • 55
  • 86

5 Answers5

50
Member
  .findOne({ country_id: 10 })
  .sort('-score')  // give me the max
  .exec(function (err, member) {

    // your callback code

  });

Check the mongoose docs for querying, they are pretty good.

If you dont't want to write the same code again you could also add a static method to your Member model like this:

memberSchema.statics.findMax = function (callback) {

  this.findOne({ country_id: 10 }) // 'this' now refers to the Member class
    .sort('-score')
    .exec(callback);
}

And call it later via Member.findMax(callback)

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
tmaximini
  • 8,403
  • 6
  • 47
  • 69
15

You do not need Mongoose documentation to do this. Plain MongoDb will do the job.

Assume you have your Member collection:

{ "_id" : ObjectId("527619d6e964aa5d2bdca6e2"), "country_id" : 10, "name" : "tes2t", "score" : 15 }
{ "_id" : ObjectId("527619cfe964aa5d2bdca6e1"), "country_id" : 10, "name" : "test", "score" : 5 }
{ "_id" : ObjectId("527619e1e964aa5d2bdca6e3"), "country_id" : 10, "name" : "tes5t", "score" : -6 }
{ "_id" : ObjectId("527619e1e964aa5d2bdcd6f3"), "country_id" : 8, "name" : "tes5t", "score" : 24 }

The following query will return you a cursor to the document, you are looking for:

 db.Member.find({country_id : 10}).sort({score : -1}).limit(1)
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • Thanks ! I have been using Mongoose all across my code and would be good if I continue doing that. – geeky_monster Nov 03 '13 at 09:56
  • 1
    Salvador Dali - Ofcourse I can insert this inbetween the Mongoose code and make it work. But I wanted to know the mongoose style of doing this. thanks !! – geeky_monster Nov 03 '13 at 13:08
7

It might be faster to use find() than findOne().

With find().limit(1) an array of the one document is returned. To get the document object, you have to do get the first array element, maxResult[0].

Making Salvador's answer more complete ...

var findQuery = db.Member.find({country_id : 10}).sort({score : -1}).limit(1);

findQuery.exec(function(err, maxResult){
    if (err) {return err;}

    // do stuff with maxResult[0]

});
Community
  • 1
  • 1
Melissa
  • 1,236
  • 5
  • 12
  • 29
3

This is quick and easy using the Mongoose Query Helpers.

The general form for this could be:

<Your_Model>.find()
   .sort("-field_to_sort_by")
   .limit(1)
   .exec( (error,data) => someFunc(error,data) {...} );

tldr: This will give you an array of a single item with the highest value in 'field_to_sort_by'. Don't forget to access it as data[0], like I did for an hour.

Long-winded: Step-by-step on what that string of functions is doing...

Your_Model.find() starts the query, no args needed.

.sort("-field_to_sort_by") sorts the everything in descending order. That minus-sign in front of the field name specifies to sort in descending order, you can discard it to sort in ascending order and thus get the document with the minimum value.

.limit(1) tells the database to only return the first document, because we only want the top-ranked document.

.exec( (error,data) => someFunc(error,data) {...} ) finally passes any error and an array containing your document to into your function. You'll find your document in data[0]

1

You can also use the $max operator:

// find the max age of all users
Users.aggregate(
    { $group: { _id: null, maxAge: { $max: '$age' }}}
  , { $project: { _id: 0, maxAge: 1 }}
  , function (err, res) {
  if (err) return handleError(err);
  console.log(res); // [ { maxAge: 98 } ]
});
Sinandro
  • 2,426
  • 3
  • 21
  • 36