संग्रह से अधिकतम मूल्य प्राप्त करने का तरीका


87

मेरे पास एक मोंगोडब संग्रह है जैसे:

db.kids.find()
//results
[
    {name:'tom', age:10},
    {name:'alice', age:12},
    ....
]

I need a query to get MAX 'age' from this collection like in SQL: SELECT MAX(age) FROM kids WHERE 1



9
you can use db.collection.find().sort({age:-1}).limit(1)
Vishwas

जवाबों:


125

As one of comments:

db.collection.find().sort({age:-1}).limit(1) // for MAX
db.collection.find().sort({age:+1}).limit(1) // for MIN

it's completely usable but i'm not sure about performance


11
In case of a large collection, it's better to define an index on age field. Then if you use db.collection.find({}, {age: 1, _id:0}).sort({age:-1}).limit(1), you probably would have a very fast Covered Query
Ali Dehghani

@AliDehghani Would this method works on mongo shards?
igonejack

72

The performance of the suggested answer is fine. According to the MongoDB documentation:

When a $sort immediately precedes a $limit, the optimizer can coalesce the $limit into the $sort. This allows the sort operation to only maintain the top n results as it progresses, where n is the specified limit, and MongoDB only needs to store n items in memory.

Changed in version 4.0.

So in the case of

db.collection.find().sort({age:-1}).limit(1)

we get only the highest element WITHOUT sorting the collection because of the mentioned optimization.


7
that documentation link is for aggregation. Are you sure find( ... ).sort( ... ).limit( ... ) is treated the same way as aggregate([{$match: ... }, {$sort: ...}, {$limit: ...}])? is there any place in the mongo docs that they mention this?
jmmut

26

what about using aggregate framework:

db.collection.aggregate({ $group : { _id: null, max: { $max : "$age" }}});

21
This is not as efficient as the sort.limit. Still, I know deep down everyone feels weird about that sort and limit...
AFP_555

@AFP_555 Really surprised to know that aggregate is slower than a sort-limit query. Thanks for sharing!
Nam G VU

1
is aggregate slower than sort-limit query?
ashusvirus

1
I do the simple test case. Create a collection with 1,000,000 documents {name: "player ", score: x}. The .find().sort({score:-1}).limit(1); take more time than .aggregate([{ $group : { _id: null, max: { $max : "$score" }}}])
tuananh

3
@tuananh, this can happen if you don't have an index on "score". In this case sort will have to do O(n log n) operations, while aggregate will only do one scan O(n). With indexed field, sort(...).limit(1) will be very fast constant time O(1) operation.
cababunga


3
db.collection.findOne().sort({age:-1}) //get Max without need for limit(1)

4
At least in Mongo 4.2, that syntax will get you a TypeError: db.collection.findOne(...).sort is not a function. collection.findOne() returns the document itself, so calling sort() on it seems unlikely to work.
Peter Hansen

3

Folks you can see what the optimizer is doing by running a plan. The generic format of looking into a plan is from the MongoDB documentation . i.e. Cursor.plan(). If you really want to dig deeper you can do a cursor.plan(true) for more details.

Having said that if you have an index, your db.col.find().sort({"field":-1}).limit(1) will read one index entry - even if the index is default ascending and you wanted the max entry and one value from the collection.

In other words the suggestions from @yogesh is correct.

Thanks - Sumit


1

Simple Explanation, if you have mongo query Response something like below - and you want only highest value from Array-> "Date"

{
  "_id": "57ee5a708e117c754915a2a2",
  "TotalWishs": 3,
  "Events": [
    "57f805c866bf62f12edb8024"
  ],
  "wish": [
    "Cosmic Eldorado  Mountain Bikes, 26-inch (Grey/White)",
    "Asics Men's Gel-Nimbus 18 Black, Snow and Fiery Red Running Shoes - 10 UK/India (45 EU) (11 US)",
    "Suunto Digital Black Dial Unisex Watch - SS018734000"
  ],
  "Date": [
    "2017-02-13T00:00:00.000Z",
    "2017-03-05T00:00:00.000Z"
  ],
  "UserDetails": [
    {
      "createdAt": "2016-09-30T12:28:32.773Z",
      "jeenesFriends": [
        "57edf8a96ad8f6ff453a384a",
        "57ee516c8e117c754915a26b",
        "58a1644b6c91d2af783770b0",
        "57ef4631b97d81824cf54795"
      ],
      "userImage": "user_profile/Male.png",
      "email": "roopak@small-screen.com",
      "fullName": "Roopak Kapoor"
    }
  ],

},

***Then you have add

Latest_Wish_CreatedDate: { $max: "$Date"},

somthing like below-

{ 
                $project : { _id: 1,
                             TotalWishs : 1 ,
                              wish:1 ,
                               Events:1, 
                               Wish_CreatedDate:1,
                               Latest_Wish_CreatedDate: { $max: "$Date"},
                            } 
            } 

And Final Query Response will be below

{
  "_id": "57ee5a708e117c754915a2a2",
  "TotalWishs": 3,
  "Events": [
    "57f805c866bf62f12edb8024"
  ],
  "wish": [
    "Cosmic Eldorado  Mountain Bikes, 26-inch (Grey/White)",
    "Asics Men's Gel-Nimbus 18 Black, Snow and Fiery Red Running Shoes - 10 UK/India (45 EU) (11 US)",
    "Suunto Digital Black Dial Unisex Watch - SS018734000"
  ],
  "Wish_CreatedDate": [
    "2017-03-05T00:00:00.000Z",
    "2017-02-13T00:00:00.000Z"
  ],
  "UserDetails": [
    {
      "createdAt": "2016-09-30T12:28:32.773Z",
      "jeenesFriends": [
        "57edf8a96ad8f6ff453a384a",
        "57ee516c8e117c754915a26b",
        "58a1644b6c91d2af783770b0",
        "57ef4631b97d81824cf54795"
      ],
      "userImage": "user_profile/Male.png",
      "email": "roopak@small-screen.com",
      "fullName": "Roopak Kapoor"
    }
  ],
  "Latest_Wish_CreatedDate": "2017-03-05T00:00:00.000Z"
},

1

For max value, we can write sql query as

select age from table_name order by age desc limit 1

same way we can write in mongodb too.

db.getCollection('collection_name').find().sort({"age" : -1}).limit(1); //max age
db.getCollection('collection_name').find().sort({"age" : 1}).limit(1); //min age

1

You can also achieve this through aggregate pipeline.

db.collection.aggregate([{$sort:{age:-1}}, {$limit:1}])

3
This has a terrible perfomance. Getting the highest value always costs O(n) without indicies. This has a performance of O(n log(n))
sb27
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.