mongodb cách nhận giá trị tối đa từ các bộ sưu tập


81

Tôi có một bộ sưu tập mongodb như:

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

Tôi cần truy vấn để lấy MAX 'tuổi' từ bộ sưu tập này như trong SQL: SELECT MAX(age) FROM kids WHERE 1



9
bạn có thể sử dụngdb.collection.find().sort({age:-1}).limit(1)
Vishwas

Câu trả lời:


118

Như một trong những nhận xét :

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

nó hoàn toàn có thể sử dụng được nhưng tôi không chắc về hiệu suất


10
Trong trường hợp một tập hợp lớn, tốt hơn nên xác định một chỉ mục trên agetrường. Sau đó, nếu bạn sử dụng db.collection.find({}, {age: 1, _id:0}).sort({age:-1}).limit(1), bạn có lẽ sẽ có một rất nhanh Bao Query
Ali Dehghani

@AliDehghani Phương pháp này có hoạt động trên các mảnh mongo không?
igonejack

68

Hiệu suất của câu trả lời gợi ý là tốt. Theo tài liệu MongoDB :

Khi $ sắp xếp ngay trước giới hạn $ , trình tối ưu hóa có thể kết hợp $ giới hạn vào $ sort. Điều này cho phép thao tác sắp xếp chỉ duy trì n kết quả hàng đầu khi nó tiến triển, trong đó n là giới hạn được chỉ định và MongoDB chỉ cần lưu trữ n mục trong bộ nhớ.

Đã thay đổi trong phiên bản 4.0.

Vì vậy, trong trường hợp của

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

chúng tôi chỉ lấy phần tử cao nhất mà KHÔNG sắp xếp bộ sưu tập vì sự tối ưu hóa đã đề cập.


6
liên kết tài liệu đó là để tổng hợp. Bạn có chắc chắn find( ... ).sort( ... ).limit( ... )được đối xử theo cùng một cách aggregate([{$match: ... }, {$sort: ...}, {$limit: ...}])? có chỗ nào trong tài liệu mongo mà họ đề cập đến điều này không?
jmmut

25

còn việc sử dụng khung tổng hợp thì sao:

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

18
Điều này không hiệu quả như sort.limit. Tuy nhiên, tôi biết trong sâu thẳm tất cả mọi người cảm thấy kỳ lạ về điều đó sắp xếp và giới hạn ...
AFP_555

@ AFP_555 Thực sự ngạc nhiên khi biết rằng tổng hợp chậm hơn truy vấn giới hạn sắp xếp. Cám ơn vì đã chia sẻ!
Nam G VU

1
tổng hợp có chậm hơn truy vấn giới hạn sắp xếp không?
ashusvirus

1
Tôi làm trường hợp thử nghiệm đơn giản. Tạo một bộ sưu tập với 1.000.000 tài liệu {name: "player", điểm số: x}. .Find (). Sort ({score: -1}). Limit (1); mất nhiều thời gian hơn .aggregate ([{$ group: {_id: null, max: {$ max: "$ score"}}}])
tuananh

3
@tuananh, điều này có thể xảy ra nếu bạn không có chỉ mục về "điểm". Trong trường hợp này, sắp xếp sẽ phải thực hiện các phép toán O (n log n), trong khi tổng hợp sẽ chỉ thực hiện một lần quét O (n). Với trường được lập chỉ mục, sắp xếp (...). Giới hạn (1) sẽ là hoạt động liên tục thời gian O (1) rất nhanh.
cababunga

9

bạn có thể sử dụng nhóm và tối đa:

db.getCollection('kids').aggregate([
    {
        $group: {
            _id: null,
            maxQuantity: {$max: "$age"}
        }
    }
])

Câu trả lời tương tự đã được đưa ra gần một năm trước.
Dan Dascalescu

1
Câu trả lời tương tự khác dường như không hoạt động - cú pháp này đúng
Zach Smith

3

Những người bạn có thể thấy trình tối ưu hóa đang làm gì bằng cách chạy một kế hoạch. Định dạng chung để xem xét một kế hoạch là từ tài liệu MongoDB . tức là Cursor.plan (). Nếu bạn thực sự muốn tìm hiểu sâu hơn, bạn có thể thực hiện một cursor.plan (true) để biết thêm chi tiết.

Đã nói rằng nếu bạn có một chỉ mục, thì db.col.find (). Sort ({"field": - 1}). Limit (1) của bạn sẽ đọc một mục nhập chỉ mục - ngay cả khi chỉ mục được mặc định tăng dần và bạn muốn mục nhập tối đa và một giá trị từ bộ sưu tập.

Nói cách khác, các đề xuất từ ​​@yogesh là đúng.

Cảm ơn - Sumit


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

4
Ít nhất trong Mongo 4.2, cú pháp đó sẽ giúp bạn có được một TypeError: db.collection.findOne(...).sort is not a function. collection.findOne () trả về chính tài liệu, vì vậy việc gọi sort () trên nó dường như không hoạt động.
Peter Hansen

1

Giải thích đơn giản, nếu bạn có truy vấn mongo Phản hồi như bên dưới - và bạn chỉ muốn giá trị cao nhất từ Mảng-> "Ngày"

{
  "_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"
    }
  ],

},

*** Sau đó, bạn có thêm

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

những thứ như dưới đây-

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

Và Phản hồi truy vấn cuối cùng sẽ ở bên dưới

{
  "_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

Đối với giá trị tối đa, chúng ta có thể viết truy vấn sql dưới dạng

select age from table_name order by age desc limit 1

giống như cách chúng ta có thể viết trong mongodb.

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

0

Bạn cũng có thể đạt được điều này thông qua đường ống tổng hợp.

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

3
Điều này có một hiệu suất khủng khiếp. Nhận được giá trị cao nhất luôn luôn có giá O(n)mà không cần chỉ dẫn. Điều này có hiệu suấtO(n log(n))
sb27
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.