Bagaimana cara mendapatkan catatan N terakhir di mongodb?

523

Saya tidak dapat menemukan di mana pun ia telah mendokumentasikan ini. Secara default, operasi find () akan mendapatkan catatan dari awal. Bagaimana saya bisa mendapatkan catatan N terakhir di mongodb?

Sunting: juga saya ingin hasil yang dikembalikan dipesan dari yang terbaru ke yang terbaru, bukan sebaliknya.

Bin Chen
sumber
7
@Haim, harap spesifik untuk menjawab, bagian mana dari halaman web yang menyelesaikan pertanyaan saya?
Bin Chen
Hai @ BinChen, saya punya masalah yang sama baru-baru ini, apakah sudah diselesaikan?
Hanton

Jawaban:

736

Jika saya mengerti pertanyaan Anda, Anda perlu mengurutkan dalam urutan naik.

Dengan asumsi Anda memiliki beberapa id atau bidang tanggal yang disebut "x", Anda akan melakukannya ...

.menyortir()


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

The 1 akan menyortir naik (yang terlama ke terbaru) dan -1 semacam akan turun (terbaru ke terlama.)

Jika Anda menggunakan bidang _id yang dibuat secara otomatis, ia memiliki tanggal yang tertanam di dalamnya ... sehingga Anda dapat menggunakannya untuk memesan dengan ...

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

Itu akan mengembalikan semua dokumen Anda yang diurutkan dari yang tertua ke yang terbaru.

Tatanan Alam


Anda juga dapat menggunakan Pesanan Alami yang disebutkan di atas ...

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

Sekali lagi, menggunakan 1 atau -1 tergantung pada urutan yang Anda inginkan.

Gunakan .limit ()


Terakhir, praktik yang baik untuk menambahkan batas saat melakukan kueri terbuka lebar semacam ini sehingga Anda bisa melakukan ...

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

atau

db.foo.find().sort({$natural:1}).limit(50);
Justin Jenkins
sumber
11
@MortezaM. Saya cukup yakin Anda telah mencampur pesanan permintaan Anda ... sort Anda () harus dijalankan terakhir, bukan yang pertama (seperti SQL ORDER BY) .find ({}). Skip (1) .limit ( 50) .sort ({"date": - 1})
Justin Jenkins
6
Apa pun itu, urutan fungsi panggilan seharusnya tidak ada hubungannya dengan hasil akhirnya.
Morteza Milani
7
@MortezaM. Tentu saja pesanan itu penting. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Tanpa urutan apa hasilnya nanti ??? Saya setuju dengan Anda bahwa pesanan terbalik ini tidak intuitif. Bagaimanapun, ini bukan SQL, harus mengikuti paradigma OO normal.
RickyA
38
namun pesanan TIDAK masalah. Yang harus Anda lakukan adalah mencobanya untuk memastikan tidak. semua ini disebut pada kursor dan diteruskan ke server sehingga server membatasi hasil semacam itu (N atas) karena hal lain tidak masuk akal.
Asya Kamsky
10
Documents mengonfirmasi bahwa pesanan tidak penting: tautan
JohnnyHK
120

Catatan terakhir yang ditambahkan N , dari yang terbaru ke yang terbaru, dapat dilihat dengan kueri ini:

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

Jika Anda menginginkannya dengan urutan terbalik:

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

Jika Anda menginstal Mongo-Hacker Anda juga dapat menggunakan:

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

Jika Anda bosan menulis perintah ini setiap saat, Anda dapat membuat fungsi khusus di ~ / .mongorc.js Anda. Misalnya

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

lalu dari jenis mongo shell saja last(N)

Trasplazio Garzuglio
sumber
1
db.collection.find().reverse().limit(1)memberi saya kesalahan... has no method reverse
Catfish
@ Kucing Anda benar, saya baru saja melihat bahwa kebalikannya () ditambahkan oleh [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), saya akan memperbarui jawaban saya. Terima kasih.
Trasplazio Garzuglio
1
db.getCollection ('COLLECTION_NAME'). find (). lewati (db.getCollection ('COLLECTION_NAME'). count () - N) bekerja dengan baik untuk saya :)
Spl2nky
Ini harus menjadi jawaban untuk pertanyaan, dan bukan jawaban oleh Justin Jenkins.
Jadiel de Armas
Tatanan alam tidak harus diandalkan; jika Anda menggunakan set replika (dan Anda seharusnya), node yang berbeda mungkin memiliki dokumen yang sama disimpan dalam urutan berbeda pada disk.
Vince Bowdren
14

Untuk mendapatkan catatan N terakhir, Anda dapat menjalankan kueri di bawah ini:

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

jika Anda hanya menginginkan satu catatan terakhir:

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

Catatan: Sebagai pengganti $ natural Anda dapat menggunakan salah satu kolom dari koleksi Anda.

Ashwini
sumber
ini berfungsi untuk saya db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Saya pikir parathensis terakhir tidak ada dalam jawaban
Ajay
Tatanan alam tidak harus diandalkan; jika Anda menggunakan set replika (dan Anda seharusnya), node yang berbeda mungkin memiliki dokumen yang sama disimpan dalam urutan berbeda pada disk.
Vince Bowdren
6

Anda dapat menggunakan sort(), limit(), skip()untuk mendapatkan N terakhir record mulai dari setiap nilai dilewati

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

Anda dapat mencoba metode ini:

Dapatkan total jumlah catatan dalam koleksi

db.dbcollection.count() 

Kemudian gunakan lewati:

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()
bello hargbola
sumber
5

Lihat di bawah Querying: Sorting and Natural Order, http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order serta sort () di bawah Metode Kursor http://www.mongodb.org/display / DOCS / Advanced + Queries

Steve Wilhelm
sumber
1
Terima kasih untuk server Anda, sudah dekat, tapi saya ingin menyimpan catatan yang dipesan dari yang terbaru ke yang terbaru, apakah mungkin?
Bin Chen
Tatanan alam tidak harus diandalkan; jika Anda menggunakan set replika (dan Anda seharusnya), node yang berbeda mungkin memiliki dokumen yang sama disimpan dalam urutan berbeda pada disk.
Vince Bowdren
Jika Anda ingin mendapatkan catatan terbaru, Anda harus mengandalkan bidang tanggal dalam dokumen.
Vince Bowdren
5

Anda tidak dapat "melewati" berdasarkan ukuran koleksi, karena itu tidak akan mempertimbangkan kondisi kueri.

Solusi yang benar adalah menyortir dari titik akhir yang diinginkan, membatasi ukuran set hasil, kemudian menyesuaikan urutan hasil jika perlu.

Berikut ini sebuah contoh, berdasarkan kode dunia nyata.

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
        });
    }
});
Marty Hirsch
sumber
Penanganan yang bagus! Akan lebih baik untuk dapat melakukan hal yang sama di tingkat permintaan. Sesuatu seperti var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust
4

@ bin-chen,

Anda dapat menggunakan agregasi untuk entri n terbaru dari subset dokumen dalam koleksi. Berikut ini contoh sederhana tanpa pengelompokan (yang akan Anda lakukan antara tahap 4 dan 5 dalam kasus ini).

Ini mengembalikan 20 entri terbaru (berdasarkan bidang yang disebut "cap waktu"), diurutkan naik. Itu kemudian memproyeksikan setiap dokumen _id, cap waktu dan apa pun_field_you_want_to_show ke hasil.

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)
}

jadi, hasilnya akan terlihat seperti:

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

Semoga ini membantu.

lauri108
sumber
1
TERIMA KASIH @ lauri108! Dari semua jawaban untuk pertanyaan ini dan yang terkait, ini adalah SATU-SATUNYA solusi yang berfungsi dan dapat diandalkan untuk "bagaimana mendapatkan DAST N TERAKHIR". Dan cukup sederhana untuk dilakukan dalam satu permintaan. Pekerjaan selesai.
randomsock
@randomsock jika Anda suka, beri suara :)
lauri108
4

Menyortir, melompati dan sebagainya bisa sangat lambat tergantung pada ukuran koleksi Anda.

Kinerja yang lebih baik akan dicapai jika koleksi Anda diindeks oleh beberapa kriteria; dan kemudian Anda bisa menggunakan kursor min ():

Pertama, indeks koleksi Anda dengan db.collectionName.setIndex( yourIndex ) Anda Anda dapat menggunakan urutan naik atau turun, yang keren, karena Anda ingin selalu "N item terakhir" ... jadi jika Anda mengindeks dengan urutan menurun, itu sama dengan mendapatkan "item N pertama" .

Kemudian Anda menemukan item pertama dari koleksi Anda dan menggunakan nilai bidang indeksnya sebagai kriteria min dalam pencarian seperti:

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

Inilah referensi untuk kursor min (): https://docs.mongodb.com/manual/reference/method/cursor.min/

João Otero
sumber
Hanya jawaban yang memperhitungkan kinerja, tambahan yang bagus :)
zardilior
Apakah jawaban ini menjamin pesanan?
zardilior
ya, itu dijamin, berdasarkan indeks Anda
João Otero
1
Rupanya Anda bisa melupakan min dan menggunakan: db.collectionName.find().hint(yourIndex).limit(N) Jika indeks dalam urutan turun Anda mendapatkan nilai minimum N.
haltux
0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

menurut Dokumentasi mongoDB :

Anda dapat menentukan {$ natural: 1} untuk memaksa kueri melakukan pemindaian koleksi ke depan.

Anda juga dapat menentukan {$ natural: -1} untuk memaksa kueri melakukan pemindaian koleksi terbalik.

Gili.il
sumber
0

gunakan operator $ slice untuk membatasi elemen array

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}` });
});

di mana geolokasi adalah array data, dari situ kita mendapatkan 5 record terakhir.

KARTHIKEYAN.A
sumber
-5

Fungsi terakhir seharusnya sort, bukan limit.

Contoh:

db.testcollection.find().limit(3).sort({timestamp:-1}); 
Ramesh Kasi
sumber
2
Ini sepertinya salah. Mengapa sortsetelah itu limit?
Acumenus