Getting the highest value of a column in MongoDB
Asked Answered
S

9

28

I've been for some help on getting the highest value on a column for a mongo document. I can sort it and get the top/bottom, but I'm pretty sure there is a better way to do it.

I tried the following (and different combinations):

transactions.find("id" => x).max({"sellprice" => 0})

But it keeps throwing errors. What's a good way to do it besides sorting and getting the top/bottom?

Thank you!

Supertax answered 21/1, 2011 at 19:32 Comment(1)
You should include the errors it's throwing.Tiddlywinks
S
48

max() does not work the way you would expect it to in SQL for Mongo. This is perhaps going to change in future versions but as of now, max,min are to be used with indexed keys primarily internally for sharding.

see http://www.mongodb.org/display/DOCS/min+and+max+Query+Specifiers

Unfortunately for now the only way to get the max value is to sort the collection desc on that value and take the first.

transactions.find("id" => x).sort({"sellprice" => -1}).limit(1).first()
Satrap answered 21/1, 2011 at 20:25 Comment(0)
M
19

Sorting might be overkill. You can just do a group by

db.messages.group(
           {key: { created_at:true },
            cond: { active:1 },
            reduce: function(obj,prev) { if(prev.cmax<obj.created_at) prev.cmax = obj.created_at; },
            initial: { cmax: **any one value** }
            });
Monto answered 25/11, 2011 at 14:0 Comment(1)
I wouldn't say it's an overkill considering this quote from the manual "When a $sort immediately precedes a $limit in the pipeline, the $sort operation only maintains the top n results as it progresses, where n is the specified limit"Trudietrudnak
P
10
db.collectionName.aggregate(
  {
    $group : 
    {
      _id  : "",
      last : 
      {
        $max : "$sellprice"
      }
    }
  }
)
Progress answered 24/5, 2013 at 18:55 Comment(0)
S
5

Example mongodb shell code for computing aggregates.

see mongodb manual entry for group (many applications) :: http://docs.mongodb.org/manual/reference/aggregation/group/#stage._S_group

In the below, replace the $vars with your collection key and target variable.

db.activity.aggregate( 
  { $group : {
      _id:"$your_collection_key", 
      min: {$min : "$your_target_variable"}, 
      max: {$max : "$your_target_variable"}
    }
  } 
)
Spindling answered 5/6, 2013 at 22:30 Comment(0)
A
3

Use aggregate():

db.transactions.aggregate([
  {$match: {id: x}},
  {$sort: {sellprice:-1}},
  {$limit: 1},
  {$project: {sellprice: 1}}
]);
Athabaska answered 23/5, 2013 at 20:13 Comment(0)
G
3

It will work as per your requirement.

transactions.find("id" => x).sort({"sellprice" => -1}).limit(1).first()
Goodtempered answered 30/3, 2015 at 11:30 Comment(1)
What's the point of this answer? Repeating the accepted answer?Schwarz
P
0

If the column's indexed then a sort should be OK, assuming Mongo just uses the index to get an ordered collection. Otherwise it's more efficient to iterate over the collection, keeping note of the largest value seen. e.g.

max = nil
coll.find("id" => x).each do |doc| 
    if max == nil or doc['sellprice'] > max then
        max = doc['sellprice'] 
    end
end

(Apologies if my Ruby's a bit ropey, I haven't used it for a long time - but the general approach should be clear from the code.)

Painless answered 21/1, 2011 at 20:32 Comment(1)
Consider to iterate with MapReduce !!! This why MongoDB is cool, else use flat files ;-)Pentheam
B
0

Assuming I was using the Ruby driver (I saw a mongodb-ruby tag on the bottom), I'd do something like the following if I wanted to get the maximum _id (assuming my _id is sortable). In my implementation, my _id was an integer.

result = my_collection.find({}, :sort => ['_id', :desc]).limit(1)

To get the minimum _id in the collection, just change :desc to :asc

Betrothed answered 20/9, 2011 at 15:36 Comment(1)
Wouldn't find_one() be better than using limit()? result = my_collection.find_one({}, :sort => ['_id', :desc])Footle
S
0

Following query does the same thing: db.student.find({}, {'_id':1}).sort({_id:-1}).limit(1)

For me, this produced following result: { "_id" : NumberLong(10934) }

Spires answered 3/11, 2014 at 16:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.