Como obter os últimos N registros no mongodb?

523

Não consigo encontrar em nenhum lugar onde isso tenha sido documentado. Por padrão, a operação find () fará com que os registros sejam iniciados. Como posso obter os últimos N registros no mongodb?

Edit: também quero que o resultado retornado seja ordenado de menos recente para o mais recente, não o inverso.

Bin Chen
fonte
7
@Haim, seja específico para responder, que parte da página da web resolve minha pergunta?
Bin Chen
Oi @BinChen, tenho o mesmo problema recentemente, está resolvido?
Hanton

Respostas:

736

Se eu entendi sua pergunta, você precisa classificar em ordem crescente.

Supondo que você tenha algum campo de identificação ou data chamado "x", você faria ...

.ordenar()


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

O 1 classificará ascendente (do mais antigo para o mais novo) e -1 classificará descendente (do mais recente para o mais antigo).

Se você usar o campo _id criado automaticamente, ele terá uma data incorporada ... para que você possa usá-lo para ordenar por ...

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

Isso retornará todos os seus documentos classificados do mais antigo para o mais novo.

Ordem natural


Você também pode usar uma ordem natural mencionada acima ...

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

Novamente, use 1 ou -1, dependendo da ordem desejada.

Use .limit ()


Por fim, é uma boa prática adicionar um limite ao fazer esse tipo de consulta aberta, para que você possa ...

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

ou

db.foo.find().sort({$natural:1}).limit(50);
Justin Jenkins
fonte
11
@MortezaM. Tenho certeza de que você tem sua ordem de consulta misturada ... seu sort () deve ser executado por último, não primeiro (como um SQL ORDER BY) .find ({}). Skip (1) .limit ( 50) .sort ({"date": - 1})
Justin Jenkins
6
Seja como for, a ordem de chamar funções não deve ter nada a ver com o resultado final.
Morteza Milani
7
@MortezaM. Claro que a ordem é importante. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Sem ordem qual seria o resultado ??? Concordo com você que essa ordem inversa não é intuitiva. Afinal, não é um SQL, ele deve seguir os paradigmas normais de OO.
RickyA
38
e ainda assim o pedido NÃO importa. Tudo o que você precisa fazer é tentar ver que não. tudo isso é chamado no cursor e passado ao servidor para que o servidor limite os resultados da classificação (N superior), pois qualquer outra coisa não faria sentido.
Asya Kamsky
10
Os documentos confirmam que o pedido não importa: link
JohnnyHK 07/07
120

Os últimos N registros adicionados, do menos recente ao mais recente, podem ser vistos com esta consulta:

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

Se você quiser na ordem inversa:

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

Se você instalar o Mongo-Hacker, também poderá usar:

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

Se você se cansar de escrever esses comandos o tempo todo, poderá criar funções personalizadas no seu ~ / .mongorc.js. Por exemplo

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

então a partir de um shell mongo basta digitar last(N)

Trasplazio Garzuglio
fonte
1
db.collection.find().reverse().limit(1)me dá o erro... has no method reverse
Catfish
@ Catfish você está certo, acabei de notar que reverse () foi adicionado por [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), vou atualizar minha resposta. Obrigado.
Trasplazio Garzuglio
1
db.getCollection ( 'COLLECTION_NAME') find () ignorar (db.getCollection ( 'COLLECTION_NAME') count () -. N).. trabalhando muito para mim :)
Spl2nky
Essa deve ser a resposta para a pergunta, e não a resposta de Justin Jenkins.
Jadiel de Armas
Não se deve confiar na ordem natural ; se você estiver usando um conjunto de réplicas (e deveria estar), nós diferentes podem ter os mesmos documentos armazenados em uma ordem diferente no disco.
Vince Bowdren
14

Para obter os últimos N registros, você pode executar a consulta abaixo:

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

se você quiser apenas um último registro:

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

Nota: No lugar de $ natural, você pode usar uma das colunas da sua coleção.

Ashwini
fonte
isso funciona para mim db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Eu acho que falta a última parathensis na resposta #
Ajay
Não se deve confiar na ordem natural ; se você estiver usando um conjunto de réplicas (e deveria estar), nós diferentes podem ter os mesmos documentos armazenados em uma ordem diferente no disco.
Vince Bowdren
6

você pode usar sort(), limit(), skip()para obter última N início registro de qualquer valor ignorado

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

Você pode tentar este método:

Obtenha o número total de registros na coleção com

db.dbcollection.count() 

Então use pular:

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

Procure em Consulta: Classificação e ordem natural, http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order , bem como sort () em Cursor Methods http://www.mongodb.org/display / DOCS / Avançado + Consultas

Steve Wilhelm
fonte
1
Obrigado pela resposta, está próximo, mas eu quero recuperar registros encomendados do menos recente para o mais recente, é possível?
Bin Chen
Não se deve confiar na ordem natural ; se você estiver usando um conjunto de réplicas (e deveria estar), nós diferentes podem ter os mesmos documentos armazenados em uma ordem diferente no disco.
Vince Bowdren
Se você deseja obter os registros mais recentes, precisará confiar em um campo de data no documento.
Vince Bowdren
5

Você não pode "pular" com base no tamanho da coleção, porque ela não levará em consideração as condições da consulta.

A solução correta é classificar a partir do ponto final desejado, limitar o tamanho do conjunto de resultados e ajustar a ordem dos resultados, se necessário.

Aqui está um exemplo, com base no código do 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
fonte
Solução agradável! Seria bom poder fazer o mesmo no nível da consulta. Algo como var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
Inwpitrust
4

@ bin-chen,

Você pode usar uma agregação para as n entradas mais recentes de um subconjunto de documentos em uma coleção. Aqui está um exemplo simplificado sem agrupamento (o que você faria entre os estágios 4 e 5 neste caso).

Isso retorna as 20 entradas mais recentes (com base em um campo chamado "registro de data e hora"), classificadas em ordem crescente. Em seguida, ele projeta cada documento _id, timestamp e qualquer que seja_field_you_want_to_show nos 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)
}

portanto, o resultado seria algo como:

{ 
    "_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 isto ajude.

lauri108
fonte
1
OBRIGADO @ lauri108! De todas as respostas para esta e outras questões relacionadas, esta é a ÚNICA solução funcional e confiável para "como obter os ÚLTIMOS DOCS". E simples o suficiente para fazer em uma consulta. Tarefa concluída.
Randomsock
@randomsock se você gosta, vote :) :)
lauri108
4

Classificar, pular etc. pode ser bem lento, dependendo do tamanho da sua coleção.

Um desempenho melhor seria alcançado se sua coleção fosse indexada por alguns critérios; e então você poderia usar o cursor min ():

Primeiro, indexe sua coleção com db.collectionName.setIndex( yourIndex ) Você pode usar ordem crescente ou decrescente, o que é legal, porque você deseja sempre os "N últimos itens" ... portanto, se você indexar por ordem decrescente, é o mesmo que obter os "primeiros N itens" .

Em seguida, você encontra o primeiro item da sua coleção e usa seus valores de campo de índice como os critérios mínimos em uma pesquisa como:

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

Aqui está a referência para o cursor min (): https://docs.mongodb.com/manual/reference/method/cursor.min/

João Otero
fonte
Única resposta que leva o desempenho em conta, grande adição :)
zardilior
Esta resposta garante ordem?
Zardilior
sim, garante, com base no seu índice
João Otero
1
Aparentemente, você pode esquecer o mínimo e usar: db.collectionName.find().hint(yourIndex).limit(N) Se o índice estiver em ordem decrescente, você obtém os N valores mínimos.
haltux 8/06
0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

de acordo com a documentação do mongoDB :

Você pode especificar {$ natural: 1} para forçar a consulta a executar uma varredura de coleção encaminhada.

Você também pode especificar {$ natural: -1} para forçar a consulta a executar uma verificação de coleção reversa.

Gili.il
fonte
0

use o operador $ slice para limitar os elementos da 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}` });
});

onde geolocalização é uma matriz de dados, obtemos os últimos 5 registros.

KARTHIKEYAN.A
fonte
-5

A última função deve ser sort, não limit.

Exemplo:

db.testcollection.find().limit(3).sort({timestamp:-1}); 
Ramesh Kasi
fonte
2
Isso parece incorreto. Por que sortseria depois limit?
Acumenos