¿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.


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

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)


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.


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

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

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 +


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

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.


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/


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.


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.


-5

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

Ejemplo:

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

2
Esto parece incorrecto. ¿Por qué sería sortdespués limit?
Acumenus
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.