¿Cómo obtener los últimos N registros en mongodb?

523

No puedo encontrar ningún lugar donde se haya documentado esto. Por defecto, la operación find () obtendrá los registros desde el principio. ¿Cómo puedo obtener los últimos N registros en mongodb?

Editar: también quiero que el resultado devuelto esté ordenado de menos reciente a más reciente, no al revés.

Bin Chen
fuente
77
@Haim, por favor sé específico para responder, ¿qué parte de la página web resuelve mi pregunta?
Bin Chen
Hola @BinChen, tengo el mismo problema recientemente, ¿está resuelto?
Hanton

Respuestas:

736

Si entiendo su pregunta, debe ordenar en orden ascendente.

Suponiendo que tiene algún campo de identificación o fecha llamado "x" que haría ...

.ordenar()


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

El 1 ordenará ascendente (más antiguo a más reciente) y -1 ordenará descendente (más nuevo a más antiguo).

Si usa el campo _id creado automáticamente , tiene una fecha incrustada ... así que puede usarlo para ordenar por ...

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

Eso devolverá todos sus documentos ordenados del más antiguo al más nuevo.

Orden natural


También puede usar un orden natural mencionado anteriormente ...

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

Nuevamente, usando 1 o -1 dependiendo del orden que desee.

Utilice .limit ()


Por último, es una buena práctica agregar un límite al hacer este tipo de consulta abierta para que pueda hacer cualquiera ...

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

o

db.foo.find().sort({$natural:1}).limit(50);
Justin Jenkins
fuente
11
@MortezaM. Estoy bastante seguro de que tiene su orden de consulta mezclado ... su sort () debe ejecutarse en último lugar, no primero (al igual que un ORDER BY de SQL) .find ({}). Skip (1) .limit ( 50) .sort ({"fecha": - 1})
Justin Jenkins
66
Sea lo que sea, el orden de las funciones de llamada no debería tener nada que ver con el resultado final.
Morteza Milani
77
@MortezaM. Por supuesto que el orden importa. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Sin orden, ¿cuál sería el resultado? Estoy de acuerdo con usted en que este orden inverso no es intuitivo. Esto no es SQL, después de todo, debe seguir los paradigmas normales de OO.
RickyA
38
Y sin embargo, el orden NO importa. Todo lo que tienes que hacer es probarlo para ver que no. todos estos se invocan en el cursor y se pasan al servidor para que el servidor limite los resultados de la clasificación (N superior) ya que cualquier otra cosa no tendría sentido.
Asya Kamsky
10
Los doctores confirman que el pedido no importa: enlace
JohnnyHK
120

Los últimos N registros agregados, de menos recientes a más recientes, se pueden ver con esta consulta:

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

Si los quieres en el orden inverso:

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

Si instala Mongo-Hacker también puede usar:

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

Si se cansa de escribir estos comandos todo el tiempo, puede crear funciones personalizadas en su ~ / .mongorc.js. P.ej

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

luego de un shell de mongo simplemente escriba last(N)

Trasplazio Garzuglio
fuente
1
db.collection.find().reverse().limit(1)me da el error... has no method reverse
Catfish
@Catfish tienes razón, me acabo de dar cuenta de que reverse () fue agregado por [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), actualizaré mi respuesta. Gracias.
Trasplazio Garzuglio
1
db.getCollection ('COLLECTION_NAME'). find (). skip (db.getCollection ('COLLECTION_NAME'). count () - N) funciona muy bien para mí :)
Spl2nky
Esta debería ser la respuesta a la pregunta, y no la respuesta de Justin Jenkins.
Jadiel de Armas
No se debe confiar en el orden natural ; Si está utilizando un conjunto de réplicas (y debería estarlo), diferentes nodos podrían tener los mismos documentos almacenados en un orden diferente en el disco.
Vince Bowdren
14

Para obtener los últimos N registros, puede ejecutar la siguiente consulta:

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

si solo quieres un último registro:

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

Nota: en lugar de $ natural, puede usar una de las columnas de su colección.

Ashwini
fuente
esto funciona para mí db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Creo que la última paratensis falta en la respuesta
Ajay
No se debe confiar en el orden natural ; Si está utilizando un conjunto de réplicas (y debería estarlo), diferentes nodos podrían tener los mismos documentos almacenados en un orden diferente en el disco.
Vince Bowdren
6

se puede utilizar sort(), limit(), skip()para obtener la última N inicio de la grabación de cualquier valor omitido

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

Puedes probar este método:

Obtenga el número total de registros en la colección con

db.dbcollection.count() 

Luego usa skip:

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

Mire en Consulta: Clasificación y orden natural, http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order , así como sort () en Métodos de cursor http://www.mongodb.org/display / DOCS / Consultas avanzadas +

Steve Wilhelm
fuente
1
Gracias por su respuesta, está cerca, pero quiero recuperar los registros ordenados del menos reciente al más reciente, ¿es posible?
Bin Chen
No se debe confiar en el orden natural ; Si está utilizando un conjunto de réplicas (y debería estarlo), diferentes nodos podrían tener los mismos documentos almacenados en un orden diferente en el disco.
Vince Bowdren
Si desea obtener los registros más recientes, deberá confiar en un campo de fecha en el documento.
Vince Bowdren
5

No puede "omitir" en función del tamaño de la colección, ya que no tendrá en cuenta las condiciones de consulta.

La solución correcta es ordenar desde el punto final deseado, limitar el tamaño del conjunto de resultados y luego ajustar el orden de los resultados si es necesario.

Aquí hay un ejemplo, basado en código del mundo real.

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
fuente
Buena solución! Sin embargo, sería bueno poder hacer lo mismo en el nivel de consulta. Algo así como var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust
4

@ bin-chen,

Puede usar una agregación para las últimas n entradas de un subconjunto de documentos en una colección. Aquí hay un ejemplo simplificado sin agrupación (que estaría haciendo entre las etapas 4 y 5 en este caso).

Esto devuelve las últimas 20 entradas (basadas en un campo llamado "marca de tiempo"), ordenadas de forma ascendente. Luego, proyecta cada documento _id, marca de tiempo y lo que sea_campo_que usted_quiere_para_ mostrar en los resultados.

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

entonces, el resultado se vería así:

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

Espero que esto ayude.

lauri108
fuente
1
GRACIAS @ lauri108! De todas las respuestas a esta y otras preguntas relacionadas, esta es LA ÚNICA solución confiable y que funciona para "cómo obtener los ÚLTIMOS DOCUMENTOS N". Y lo suficientemente simple como para hacer en una consulta. Trabajo hecho.
randomsock el
@randomsock si te gusta, vota :)
lauri108
4

Ordenar, omitir, etc. puede ser bastante lento dependiendo del tamaño de su colección.

Se lograría un mejor rendimiento si tiene su colección indexada por algunos criterios; y luego podrías usar el cursor min ():

Primero, indexe su colección con db.collectionName.setIndex( yourIndex ) Puede usar el orden ascendente o descendente, lo cual es genial, porque siempre desea los "N últimos elementos" ... así que si indexa en orden descendente es lo mismo que obtener los "primeros N elementos" .

Luego, encuentra el primer elemento de su colección y utiliza sus valores de campo de índice como criterios mínimos en una búsqueda como:

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

Aquí está la referencia para el cursor min (): https://docs.mongodb.com/manual/reference/method/cursor.min/

João Otero
fuente
Respuesta única que tiene en cuenta el rendimiento, una gran adición :)
zardilior
¿Esta respuesta garantiza el orden?
zardilior
sí, garantiza, según su índice
João Otero
1
Aparentemente, puede olvidar el mínimo y usar: db.collectionName.find().hint(yourIndex).limit(N) Si el índice está en orden descendente, obtiene los N valores mínimos.
haltux
0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

de acuerdo con la documentación de mongoDB :

Puede especificar {$ natural: 1} para forzar a la consulta a realizar una exploración de recopilación de reenvíos.

También puede especificar {$ natural: -1} para forzar a la consulta a realizar una exploración de recopilación inversa.

Gili.il
fuente
0

use el operador $ slice para limitar los elementos de la matriz

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

donde la geolocalización es una matriz de datos, de eso obtenemos los últimos 5 registros.

KARTHIKEYAN.A
fuente
-5

La última función debería ser sort, no limit.

Ejemplo:

db.testcollection.find().limit(3).sort({timestamp:-1}); 
Ramesh Kasi
fuente
2
Esto parece incorrecto. ¿Por qué sería sortdespués limit?
Acumenus