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.


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

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)


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.


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

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

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


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

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.


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/


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


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.


-5

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

Exemplo:

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

2
Isso parece incorreto. Por que sortseria depois limit?
— Acumenos
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.