Làm thế nào để có được các bản ghi N cuối cùng trong mongodb?


523

Tôi không thể tìm thấy bất cứ nơi nào nó đã được ghi nhận điều này. Theo mặc định, thao tác find () sẽ lấy các bản ghi từ đầu. Làm thế nào tôi có thể nhận được các bản ghi N cuối cùng trong mongodb?

Chỉnh sửa: tôi cũng muốn kết quả trả về được sắp xếp theo thứ tự từ ít gần đây nhất đến gần đây nhất, chứ không phải ngược lại.


7
@ Yêu cầu, xin hãy cụ thể để trả lời, phần nào của trang web giải quyết câu hỏi của tôi?
Bin Chen

Xin chào @BinChen, tôi có cùng một vấn đề gần đây, nó đã được giải quyết chưa?
Hanton

Câu trả lời:


736

Nếu tôi hiểu câu hỏi của bạn, bạn cần sắp xếp theo thứ tự tăng dần.

Giả sử bạn có một số trường id hoặc ngày gọi là "x", bạn sẽ làm ...

.sort ()


db.foo.find().sort({x:1});

Số 1 sẽ sắp xếp tăng dần (cũ nhất đến mới nhất) và -1 sẽ sắp xếp giảm dần (mới nhất đến cũ nhất).

Nếu bạn sử dụng trường _id được tạo tự động, nó có một ngày được nhúng trong đó ... vì vậy bạn có thể sử dụng trường đó để đặt hàng theo ...

db.foo.find().sort({_id:1});

Điều đó sẽ trả lại tất cả các tài liệu của bạn được sắp xếp từ cũ nhất đến mới nhất.

Trật tự tự nhiên


Bạn cũng có thể sử dụng Đơn hàng tự nhiên được đề cập ở trên ...

db.foo.find().sort({$natural:1});

Một lần nữa, sử dụng 1 hoặc -1 tùy thuộc vào thứ tự bạn muốn.

Sử dụng .limit ()


Cuối cùng, nên thêm một giới hạn khi thực hiện loại truy vấn mở rộng này để bạn có thể thực hiện ...

db.foo.find().sort({_id:1}).limit(50);

hoặc là

db.foo.find().sort({$natural:1}).limit(50);

11
@MortezaM. Tôi khá chắc chắn rằng bạn đã sắp xếp thứ tự truy vấn của mình ... sắp xếp () của bạn sẽ được chạy sau cùng, không phải trước tiên (giống như lệnh SQL ORDER BY) .find ({}). Skip (1) .limit ( 50) .sort ({"ngày": - 1})
Justin Jenkins

6
Dù là gì đi nữa, thứ tự của các hàm gọi sẽ không liên quan gì đến kết quả cuối cùng.
Morteza Milani

7
@MortezaM. Tất nhiên thứ tự quan trọng. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Không có thứ tự kết quả sẽ ra sao ??? Tôi đồng ý với bạn rằng thứ tự đảo ngược này không trực quan. Đây không phải là SQL sau tất cả, nó phải tuân theo các mô hình OO bình thường.
RickyA

38
nhưng thứ tự KHÔNG quan trọng. Tất cả bạn phải làm là thử nó để thấy rằng nó không. tất cả những thứ này được gọi trên con trỏ và được chuyển đến máy chủ để máy chủ giới hạn kết quả của loại (N hàng đầu) vì mọi thứ khác sẽ không có ý nghĩa.
Asya Kamsky

10
Tài liệu xác nhận rằng thứ tự không quan trọng: liên kết
JohnnyHK

120

Có thể thấy N bản ghi cuối cùng , từ ít gần đây đến gần đây nhất với truy vấn này:

db.collection.find().skip(db.collection.count() - N)

Nếu bạn muốn chúng theo thứ tự ngược lại:

db.collection.find().sort({ $natural: -1 }).limit(N)

Nếu bạn cài đặt Mongo-Hacker, bạn cũng có thể sử dụng:

db.collection.find().reverse().limit(N)

Nếu bạn cảm thấy mệt mỏi khi phải viết các lệnh này mọi lúc, bạn có thể tạo các hàm tùy chỉnh trong ~ / .mongorc.js của mình. Ví dụ

function last(N) {
    return db.collection.find().skip(db.collection.count() - N);
}

sau đó từ một vỏ mongo chỉ cần gõ last(N)


1
db.collection.find().reverse().limit(1)cho tôi biết lỗi... has no method reverse
Catfish

@Catfish bạn nói đúng, tôi chỉ nhận thấy rằng Reverse () đã được thêm bởi [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), tôi sẽ cập nhật câu trả lời của tôi. Cảm ơn.
Trasplazio Garzuglio

1
db.getCollection ( 'COLLECTION_NAME') tìm () bỏ qua (db.getCollection ( 'COLLECTION_NAME') count () -. N).. làm việc tuyệt vời cho tôi :)
Spl2nky

Đây phải là câu trả lời cho câu hỏi, và không phải là câu trả lời của Justin Jenkins.
Jadiel de Armas

Trật tự tự nhiên không nên dựa vào; nếu bạn đang sử dụng một bộ bản sao (và bạn nên như vậy), các nút khác nhau có thể có cùng một tài liệu được lưu trữ theo thứ tự khác trên đĩa.
Vince Bowdren

14

Để có được bản ghi N cuối cùng, bạn có thể thực hiện truy vấn bên dưới:

db.yourcollectionname.find({$query: {}, $orderby: {$natural : -1}}).limit(yournumber)

nếu bạn chỉ muốn một bản ghi cuối cùng:

db.yourcollectionname.findOne({$query: {}, $orderby: {$natural : -1}})

Lưu ý: Thay cho $ tự nhiên, bạn có thể sử dụng một trong các cột trong bộ sưu tập của mình.


cái này hoạt động với tôi db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ Natural: -1}}). Tôi nghĩ rằng parathensis cuối cùng bị thiếu trong câu trả lời
Ajay

Trật tự tự nhiên không nên dựa vào; nếu bạn đang sử dụng một bộ bản sao (và bạn nên như vậy), các nút khác nhau có thể có cùng một tài liệu được lưu trữ theo thứ tự khác trên đĩa.
Vince Bowdren

6

bạn có thể sử dụng sort(), limit(), skip()để có được N cuối cùng bắt đầu ghi lại từ bất kỳ giá trị bỏ qua

db.collections.find().sort(key:value).limit(int value).skip(some int value);

6

Bạn có thể thử phương pháp này:

Lấy tổng số hồ sơ trong bộ sưu tập với

db.dbcollection.count() 

Sau đó sử dụng bỏ qua:

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()

5

Xem trong Truy vấn: Sắp xếp và thứ tự tự nhiên, http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order cũng như sort () trong Phương thức con trỏ http://www.mongodb.org/display / DOCS / Nâng cao + Truy vấn


1
Cảm ơn anwser của bạn, nó rất gần, nhưng tôi muốn giữ lại các hồ sơ được đặt hàng từ ít gần đây đến gần đây nhất, liệu có thể?
Bin Chen

Trật tự tự nhiên không nên dựa vào; nếu bạn đang sử dụng một bộ bản sao (và bạn nên như vậy), các nút khác nhau có thể có cùng một tài liệu được lưu trữ theo thứ tự khác trên đĩa.
Vince Bowdren

Nếu bạn muốn có được các bản ghi gần đây nhất, bạn sẽ phải dựa vào trường ngày trong tài liệu.
Vince Bowdren

5

Bạn không thể "bỏ qua" dựa trên kích thước của bộ sưu tập, vì nó sẽ không tính đến các điều kiện truy vấn.

Giải pháp đúng là sắp xếp từ điểm cuối mong muốn, giới hạn kích thước của tập kết quả, sau đó điều chỉnh thứ tự kết quả nếu cần.

Dưới đây là một ví dụ, dựa trên mã thế giới thực.

var query = collection.find( { conditions } ).sort({$natural : -1}).limit(N);

query.exec(function(err, results) {
    if (err) { 
    }
    else if (results.length == 0) {
    }
    else {
        results.reverse(); // put the results into the desired order
        results.forEach(function(result) {
            // do something with each result
        });
    }
});

Cách giải quyết tốt đẹp! Sẽ rất tốt để có thể làm điều tương tự ở cấp truy vấn. Một cái gì đó như var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust

4

@ bin-chen,

Bạn có thể sử dụng tổng hợp cho n mục mới nhất của một tập hợp con các tài liệu trong bộ sưu tập. Đây là một ví dụ đơn giản mà không cần nhóm (mà bạn sẽ thực hiện giữa giai đoạn 4 và 5 trong trường hợp này).

Điều này trả về 20 mục mới nhất (dựa trên một trường gọi là "dấu thời gian"), được sắp xếp tăng dần. Sau đó, nó chiếu từng tài liệu _id, dấu thời gian và bất cứ điều gì_field_you_want_to_show vào kết quả.

var pipeline = [
        {
            "$match": { //stage 1: filter out a subset
                "first_field": "needs to have this value",
                "second_field": "needs to be this"
            }
        },
        {
            "$sort": { //stage 2: sort the remainder last-first
                "timestamp": -1
            }
        },
        {
            "$limit": 20 //stage 3: keep only 20 of the descending order subset
        },
        {
            "$sort": {
                "rt": 1 //stage 4: sort back to ascending order
            }
        },
        {
            "$project": { //stage 5: add any fields you want to show in your results
                "_id": 1,
                "timestamp" : 1,
                "whatever_field_you_want_to_show": 1
            }
        }
    ]

yourcollection.aggregate(pipeline, function resultCallBack(err, result) {
  // account for (err)
  // do something with (result)
}

vì vậy, kết quả sẽ trông giống như:

{ 
    "_id" : ObjectId("5ac5b878a1deg18asdafb060"),
    "timestamp" : "2018-04-05T05:47:37.045Z",
    "whatever_field_you_want_to_show" : -3.46000003814697
}
{ 
    "_id" : ObjectId("5ac5b878a1de1adsweafb05f"),
    "timestamp" : "2018-04-05T05:47:38.187Z",
    "whatever_field_you_want_to_show" : -4.13000011444092
}

Hi vọng điêu nay co ich.


1
CẢM ƠN BẠN @ lauri108! Trong tất cả các câu trả lời cho câu hỏi này và các câu hỏi liên quan, đây là giải pháp DUY NHẤT và đáng tin cậy để "làm thế nào để có được LAST N DOCS". Và đủ đơn giản để làm trong một truy vấn. Công việc hoàn thành.
randomsock

@randomsock nếu bạn thích nó, hãy bình chọn :)
lauri108

4

Sắp xếp, bỏ qua và có thể khá chậm tùy thuộc vào kích thước của bộ sưu tập của bạn.

Một hiệu suất tốt hơn sẽ đạt được nếu bạn có bộ sưu tập của mình được lập chỉ mục theo một số tiêu chí; và sau đó bạn có thể sử dụng con trỏ min ():

Đầu tiên, lập chỉ mục bộ sưu tập của bạn với db.collectionName.setIndex( yourIndex ) Bạn có thể sử dụng thứ tự tăng dần hoặc giảm dần, điều này thật tuyệt, bởi vì bạn luôn muốn "N mục cuối" ... vì vậy nếu bạn lập chỉ mục bằng cách giảm thứ tự thì nó cũng giống như nhận "N mục đầu tiên" .

Sau đó, bạn tìm mục đầu tiên của bộ sưu tập của mình và sử dụng các giá trị trường chỉ mục của nó làm tiêu chí tối thiểu trong tìm kiếm như:

db.collectionName.find().min(minCriteria).hint(yourIndex).limit(N)

Đây là tài liệu tham khảo cho con trỏ min (): https://docs.mongodb.com/manual/reference/method/cthon.min/


Chỉ có câu trả lời có tính đến hiệu suất, bổ sung tuyệt vời :)
zardilior

Liệu câu trả lời này có đảm bảo trật tự?
zardilior

vâng, nó đảm bảo, dựa trên chỉ số của bạn
João Otero

1
Rõ ràng bạn chỉ có thể quên min và sử dụng: db.collectionName.find().hint(yourIndex).limit(N) Nếu chỉ mục theo thứ tự giảm dần, bạn nhận được N giá trị tối thiểu.
tạm dừng


0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

theo Tài liệu mongoDB :

Bạn có thể chỉ định {$ tự nhiên: 1} để buộc truy vấn thực hiện quét bộ sưu tập chuyển tiếp.

Bạn cũng có thể chỉ định {$ tự nhiên: -1} để buộc truy vấn thực hiện quét bộ sưu tập ngược.


0

sử dụng toán tử $ lát để giới hạn các phần tử mảng

GeoLocation.find({},{name: 1, geolocation:{$slice: -5}})
    .then((result) => {
      res.json(result);
    })
    .catch((err) => {
      res.status(500).json({ success: false, msg: `Something went wrong. ${err}` });
});

trong đó vị trí địa lý là mảng dữ liệu, từ đó chúng tôi nhận được 5 bản ghi cuối cùng.


-5

Chức năng cuối cùng nên sort, không limit.

Thí dụ:

db.testcollection.find().limit(3).sort({timestamp:-1}); 

2
Điều này có vẻ không chính xác. Tại sao sẽ sortlà sau limit?
Acumenus
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.