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.


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

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)


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.


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

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

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


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

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.


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/


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.


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.


-5

Fungsi terakhir seharusnya sort, bukan limit.

Contoh:

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

2
Ini sepertinya salah. Mengapa sortsetelah itu limit?
Acumenus
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.