Come ottenere gli ultimi N record in mongodb?


523

Non riesco a trovare da nessuna parte è stato documentato questo. Per impostazione predefinita, l'operazione find () otterrà i record dall'inizio. Come posso ottenere gli ultimi N record in mongodb?

Modifica: voglio anche il risultato restituito ordinato dal meno recente al più recente, non il contrario.


7
@Haim, per favore sii specifico per rispondere, quale parte della pagina web risolve la mia domanda?
Bin Chen,

Ciao @BinChen, ho lo stesso problema di recente, è risolto?
Hanton,

Risposte:


736

Se capisco la tua domanda, devi ordinare in ordine crescente.

Supponendo che tu abbia un campo ID o data chiamato "x" dovresti fare ...

.ordinare()


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

Il 1 fascicolerà ascendente (vecchio al più recente) e -1 in ordine discendente (più recente.)

Se usi il campo _id creato automaticamente ha una data incorporata in esso ... quindi puoi usarlo per ordinare per ...

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

Ciò restituirà tutti i tuoi documenti ordinati dal più vecchio al più recente.

Ordine naturale


Puoi anche usare un ordine naturale menzionato sopra ...

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

Ancora una volta, utilizzando 1 o -1 a seconda dell'ordine desiderato.

Usa .limit ()


Infine, è buona norma aggiungere un limite quando si esegue questo tipo di query completamente aperta in modo che sia possibile ...

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

o

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

11
@MortezaM. Sono abbastanza sicuro che il tuo ordine di query sia confuso ... il tuo sort () dovrebbe essere eseguito per ultimo, non prima (proprio come un SQL ORDER BY) .find ({}). Skip (1) .limit ( 50) .sort ({"data": - 1})
Justin Jenkins il

6
Qualunque cosa sia, l'ordine delle funzioni di chiamata non dovrebbe avere nulla a che fare con il risultato finale.
Morteza Milani,

7
@MortezaM. Naturalmente l'ordine conta. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Senza ordine quale sarebbe il risultato ??? Sono d'accordo con te che questo ordine inverso non è intuitivo. Questo non è SQL dopo tutto, dovrebbe seguire i normali paradigmi OO.
Ricky,

38
eppure l'ordine NON ha importanza. Tutto quello che devi fare è provarlo per vedere che non lo fa. tutti questi vengono chiamati sul cursore e passati al server in modo che il server limiti i risultati dell'ordinamento (in alto a N) poiché qualsiasi altra cosa non avrebbe senso.
Asya Kamsky,

10
I documenti confermano che l'ordine non ha importanza: link
JohnnyHK

120

Gli ultimi N record aggiunti, dal meno recente al più recente, possono essere visualizzati con questa query:

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

Se li vuoi nell'ordine inverso:

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

Se installi Mongo-Hacker puoi anche usare:

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

Se ti stanchi di scrivere questi comandi per tutto il tempo, puoi creare funzioni personalizzate nel tuo ~ / .mongorc.js. Per esempio

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

quindi da una shell mongo basta digitare last(N)


1
db.collection.find().reverse().limit(1)mi dà l'errore... has no method reverse
Catfish

@Catfish hai ragione, ho appena notato che reverse () è stato aggiunto da [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), aggiornerò la mia risposta. Grazie.
Trasplazio Garzuglio,

1
db.getCollection ('COLLECTION_NAME'). find (). skip (db.getCollection ('COLLECTION_NAME'). count () - N) funziona benissimo per me :)
Spl2nky

Questa dovrebbe essere la risposta alla domanda e non la risposta di Justin Jenkins.
Jadiel de Armas,

L'ordine naturale non dovrebbe essere invocato; se stai usando un set di repliche (e dovresti esserlo), diversi nodi potrebbero avere gli stessi documenti archiviati in un ordine diverso sul disco.
Vince Bowdren,

14

Per ottenere gli ultimi N record è possibile eseguire la query seguente:

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

se vuoi solo un ultimo record:

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

Nota: al posto di $ natural puoi usare una delle colonne della tua collezione.


questo funziona per me db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Penso che l'ultima paratensia manchi nella risposta
Ajay,

L'ordine naturale non dovrebbe essere invocato; se stai usando un set di repliche (e dovresti esserlo), diversi nodi potrebbero avere gli stessi documenti archiviati in un ordine diverso sul disco.
Vince Bowdren,

6

è possibile utilizzare sort(), limit(), skip()per arrivare all'ultimo N inizio registrare da qualsiasi valore saltato

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

6

Puoi provare questo metodo:

Ottieni il numero totale di record nella raccolta con

db.dbcollection.count() 

Quindi utilizzare skip:

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

5

1
Grazie per la tua risposta, è vicino, ma voglio recuperare i record ordinati dal meno recente al più recente, è possibile?
Bin Chen,

L'ordine naturale non dovrebbe essere invocato; se stai usando un set di repliche (e dovresti esserlo), diversi nodi potrebbero avere gli stessi documenti archiviati in un ordine diverso sul disco.
Vince Bowdren,

Se vuoi ottenere i record più recenti, dovrai fare affidamento su un campo data nel documento.
Vince Bowdren,

5

Non è possibile "saltare" in base alla dimensione della raccolta, perché non terrà conto delle condizioni della query.

La soluzione corretta è ordinare dal punto finale desiderato, limitare la dimensione del set di risultati, quindi regolare l'ordine dei risultati, se necessario.

Ecco un esempio, basato sul codice del mondo reale.

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

Bella soluzione! Sarebbe bello poter fare lo stesso a livello di query. Qualcosa del genere var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
Inwpitrust,

4

@ Bin-chen,

È possibile utilizzare un'aggregazione per le ultime n voci di un sottoinsieme di documenti in una raccolta. Ecco un esempio semplificato senza raggruppamento (cosa che faresti tra le fasi 4 e 5 in questo caso).

Ciò restituisce le ultime 20 voci (basate su un campo chiamato "timestamp"), ordinate in ordine crescente. Quindi proietta ogni documento _id, timestamp e whatever_field_you_want_to_show nei risultati.

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

quindi, il risultato sarebbe simile a:

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

Spero che sia di aiuto.


1
GRAZIE @ lauri108! Di tutte le risposte a questa e alle relative domande, questa è L'UNICA soluzione funzionante e affidabile per "come ottenere gli ULTIMI DOCUMENTI". E abbastanza semplice da fare in una query. Lavoro fatto.
randomsock,

@randomsock se ti piace,
votalo

4

Ordinamento, salto e così via possono essere piuttosto lenti a seconda delle dimensioni della tua raccolta.

Una prestazione migliore sarebbe raggiunta se la tua collezione fosse indicizzata secondo alcuni criteri; e quindi potresti usare il cursore min ():

Innanzitutto, indicizza la tua raccolta con db.collectionName.setIndex( yourIndex ) Puoi usare l'ordine crescente o decrescente, il che è interessante, perché vuoi sempre gli "N ultimi elementi" ... quindi se indicizzi in ordine decrescente è lo stesso che ottenere i "primi N elementi" .

Quindi trovi il primo elemento della tua raccolta e utilizzi i suoi valori del campo indice come criterio minimo in una ricerca come:

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

Ecco il riferimento per il cursore min (): https://docs.mongodb.com/manual/reference/method/cursor.min/



Questa risposta garantisce l'ordine?
zardilior,

sì, garantisce, in base al tuo indice
João Otero,

1
Apparentemente puoi semplicemente dimenticare il minimo e usare: db.collectionName.find().hint(yourIndex).limit(N) Se l'indice è in ordine decrescente ottieni i valori N minimi.
haltux,


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

secondo la documentazione di mongoDB :

È possibile specificare {$ natural: 1} per forzare la query a eseguire una scansione della raccolta in avanti.

Puoi anche specificare {$ natural: -1} per forzare la query ad eseguire una scansione inversa della raccolta.


0

utilizzare l' operatore $ slice per limitare gli elementi dell'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}` });
});

dove la geolocalizzazione è una matrice di dati, da cui otteniamo gli ultimi 5 record.


-5

L'ultima funzione dovrebbe essere sort, no limit.

Esempio:

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

2
Questo sembra errato. Perché sarebbe sortdopo limit?
Acumenus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.