Mongodb'da son N kayıtları nasıl alabilirim?


523

Bunu belgelediği hiçbir yerde bulamıyorum. Varsayılan olarak, find () işlemi kayıtları en baştan alır. Mongodb'daki son N kayıtlarını nasıl alabilirim?

Düzenleme: Ayrıca ben döndürülen sonuç daha az en son gelen sipariş, ters değil istiyorum.


7
@Hayır, lütfen yanıtlamaya özel olun, web sayfasının hangi kısmı sorumu çözüyor?
Bin Chen

Merhaba @BinChen, son zamanlarda aynı sorunu var, çözüldü mü?
Hanton

Yanıtlar:


736

Sorunuzu anlarsam artan düzende sıralamanız gerekir.

"X" adında bir kimlik veya tarih alanınız olduğunu varsayarsak ...

.çeşit()


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

1 artan sıralamak (eski yeni kadar) ve olacak -1 azalan sırada olacak (yeni eski için).

Otomatik oluşturulan _id alanını kullanırsanız, içine gömülü bir tarihi vardır ... böylece bunu sipariş vermek için kullanabilirsiniz ...

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

Bu, en eskiden en yeniye doğru sıralanan tüm dokümanlarınızı geri döndürür.

Doğal Düzen


Yukarıda belirtilen bir Doğal Düzeni de kullanabilirsiniz ...

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

Yine, istediğiniz sıraya bağlı olarak 1 veya -1'i kullanın .

.Limit () kullanın


Son olarak, bu tür geniş açık sorgu yaparken bir sınır eklemek iyi bir uygulamadır, böylece her ikisini de yapabilirsiniz ...

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

veya

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

11
@MortezaM. Sorgu siparişinizi karıştırdığınızdan eminim ... sıralama () en son çalıştırılmalı, ilk önce değil (bir SQL ORDER BY gibi) .find ({}). Skip (1) .limit ( 50) .sort ({"date": - 1})
Justin Jenkins

6
Ne olursa olsun, çağrı fonksiyonlarının sırasının sonuçla bir ilgisi olmamalıdır.
Morteza Milani

7
@MortezaM. Tabii ki düzen önemlidir. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Hiçbir sipariş ile sonuç ne olurdu ??? Bu ters düzenin sezgisel olmadığını kabul ediyorum. Sonuçta bu normal OO paradigmalarını izlemelidir.
RickyA

38
ve yine de sipariş önemli değil. Yapmanız gereken tek şey olmadığını görmek için deneyin. bunların tümü imleç üzerinde çağrılır ve sunucuya aktarılır, böylece sunucu sıralama sonuçlarını (ilk N) başka hiçbir şey mantıklı olmayacak şekilde sınırlar.
Asya Kamsky

10
Dokümanlar siparişin önemli olmadığını doğruladı: bağlantı
JohnnyHK

120

Geçen N En son az eskiye doğru, kayıtları eklenen, bu sorgu ile görülebilir:

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

Onları ters sırada istiyorsanız:

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

Mongo-Hacker'ı yüklerseniz şunları da kullanabilirsiniz:

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

Bu komutları her zaman yazmaktan sıkılırsanız ~ / .mongorc.js dosyasında özel işlevler oluşturabilirsiniz. Örneğin

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

sonra bir mongo kabuğundan last(N)


1
db.collection.find().reverse().limit(1)bana hata veriyor... has no method reverse
Yayın

@Catfish haklısın, sadece [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ) tarafından ters () eklendiğini fark ettim, cevabımı güncelleyeceğim. Teşekkürler.
Trasplazio Garzuglio

1
db.getCollection ('COLLECTION_NAME'). bul (). skip (db.getCollection ('COLLECTION_NAME'). say () - N) benim için harika çalışıyor :)
Spl2nky

Bu sorunun cevabı olmalı, Justin Jenkins'in yanıtı değil.
Jadiel de Armas

Doğal düzen olmalıdır değil güvenilemez; bir çoğaltma kümesi kullanıyorsanız (ve olmanız gerekir), farklı düğümlerin aynı belgelerin diskte farklı bir sırayla depolanmış olması da mümkündür.
Vince Bowdren

14

Son N kaydı almak için aşağıdaki sorguyu yürütebilirsiniz:

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

yalnızca son bir kayıt istiyorsanız:

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

Not: $ natural yerine koleksiyonunuzdaki sütunlardan birini kullanabilirsiniz.


bu benim için çalışıyor db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Bence son parathensis cevapta eksik
Ajay

Doğal düzen olmalıdır değil güvenilemez; bir çoğaltma kümesi kullanıyorsanız (ve olmanız gerekir), farklı düğümlerin aynı belgelerin diskte farklı bir sırayla depolanmış olması da mümkündür.
Vince Bowdren

6

kullanabilirsiniz sort(), limit(), skip()herhangi Atlanan değerden son N rekor başlamaya

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

6

Bu yöntemi deneyebilirsiniz:

İle koleksiyondaki toplam kayıt sayısını alın

db.dbcollection.count() 

Sonra skip'i kullanın:

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

5

1
Anwser'ınız için teşekkürler, yakın, ama daha azdan en yeniye sipariş edilen kayıtları iade etmek istiyorum, mümkün mü?
Bin Chen

Doğal düzen olmalıdır değil güvenilemez; bir çoğaltma kümesi kullanıyorsanız (ve olmanız gerekir), farklı düğümlerin aynı belgelerin diskte farklı bir sırayla depolanmış olması da mümkündür.
Vince Bowdren

En son kayıtları almak istiyorsanız, belgedeki bir tarih alanına güvenmeniz gerekir.
Vince Bowdren

5

Sorgu koşullarını dikkate almayacağı için koleksiyonun boyutuna göre "atlayamazsınız".

Doğru çözüm, istenen bitiş noktasından sıralamak, sonuç kümesinin boyutunu sınırlamak, ardından gerekirse sonuçların sırasını ayarlamaktır.

İşte gerçek dünya koduna dayanan bir örnek.

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

Güzel bir çözüm! Sorgu düzeyinde aynı şeyi yapabilmek güzel olurdu. Gibi bir şey var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust

4

@ Bin-chen

Bir koleksiyondaki belge alt kümesinin en son n girdisi için bir toplama kullanabilirsiniz. İşte gruplandırılmadan basitleştirilmiş bir örnek (bu durumda aşama 4 ve 5 arasında yapacağınız).

Bu, artan olarak sıralanmış, en son 20 girişi ("zaman damgası" adı verilen bir alana göre) döndürür. Daha sonra _id, timetamp ve whatever_field_you_want_to_show belgelerini sonuçlara yansıtır.

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

böylece sonuç şöyle görünecektir:

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

Bu yardımcı olur umarım.


1
TEŞEKKÜRLER @ lauri108! Bu ve ilgili soruların tüm cevapları arasında, bu "SON N BELGELER nasıl elde edilir" için SADECE çalışan ve güvenilir bir çözümdür. Ve tek bir sorguda yapmak için yeterince basit. İş bitmiş.
randomsock

@randomsock İsterseniz, oy verin :)
lauri108

4

Sıralama, atlama vb. Koleksiyonunuzun boyutuna bağlı olarak oldukça yavaş olabilir.

Koleksiyonunuzun bazı ölçütlere göre dizine eklenmesi durumunda daha iyi bir performans elde edilir; ve sonra min () imlecini kullanabilirsiniz:

İlk olarak, koleksiyonunuzu dizine ekleyin db.collectionName.setIndex( yourIndex ) Artan veya azalan düzeni kullanabilirsiniz, bu da iyidir, çünkü her zaman "N son öğe" ... .

Ardından koleksiyonunuzun ilk öğesini bulursunuz ve dizin alanı değerlerini aşağıdaki gibi bir aramada min kriteri olarak kullanırsınız:

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

Min () imlecinin referansı: https://docs.mongodb.com/manual/reference/method/cursor.min/


Sadece performansı dikkate alan cevap, büyük bir ek :)
zardilior

Bu cevap düzeni garanti ediyor mu?
zardilior

evet, endeksinize göre garanti eder
João Otero

1
Görünüşe göre min'i unutabilir ve kullanabilirsiniz: db.collectionName.find().hint(yourIndex).limit(N) Dizin azalan sıradaysa, N minimum değerini alırsınız.
haltux


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

mongoDB Belgelerine göre :

Sorguyu ileriye doğru toplama taraması yapmaya zorlamak için {$ natural: 1} belirtebilirsiniz.

Ayrıca sorguyu ters toplama taraması yapmaya zorlamak için {$ natural: -1} belirtebilirsiniz.


0

kullanım dizi öğelerini sınırlamak $ slice operatörünü

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

burada coğrafi konum veri dizisidir, bundan son 5 kayıt alırız.


-5

Son işlev olmalı sort, değillimit .

Misal:

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

2
Bu yanlış görünüyor. Neden olur sortsonra olması limit?
Acumenus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.