如何获取mongodb中的最后N条记录?

Bin*_*hen 474 record mongodb

我无法找到任何记录在案的地方.默认情况下,find()操作将从头开始获取记录.我怎样才能获得mongodb中的最后N条记录?

编辑:我也希望返回的结果从最近到最近排序,而不是相反.

Jus*_*ins 671

如果我理解你的问题,你需要按升序排序.

假设你有一些名为"x"的id或日期字段你会...

.分类()


db.foo.find().sort({x:1});
Run Code Online (Sandbox Code Playgroud)

1将升序(最旧到最新)和-1将降序(从最新到最旧的).

如果您使用自动创建的_id字段,则会在其中嵌入日期...因此您可以使用它来按顺序排序...

db.foo.find().sort({_id:1});
Run Code Online (Sandbox Code Playgroud)

这将返回从最旧到最新排序的所有文档.

自然秩序


您也可以使用上面提到的自然顺序 ......

db.foo.find().sort({$natural:1});
Run Code Online (Sandbox Code Playgroud)

同样,根据您想要的顺序使用1-1.

使用.limit()


最后,在进行这种大开放查询时添加限制是一个好习惯,这样你就可以做到...

db.foo.find().sort({_id:1}).limit(50);
Run Code Online (Sandbox Code Playgroud)

要么

db.foo.find().sort({$natural:1}).limit(50);
Run Code Online (Sandbox Code Playgroud)

  • 然而订单无关紧要.你所要做的就是试着看它没有.所有这些都在游标上调用并传递给服务器,因此服务器限制排序结果(前N个),因为其他任何东西都没有意义. (32认同)
  • @MortezaM.我很确定你的查询顺序已经混淆了......你的sort()应该最后运行,而不是第一次运行(很像SQL ORDER BY)**.find({}).skip(1).极限(50)的.sort({ "日期": - 1})** (10认同)
  • @MortezaM.当然订单很重要.`item = 3; item.add(3).divide(3)== 2; item.divide(3).add(3)== 4;`没有命令会有什么结果??? 我同意你的看法,这种颠倒的顺序并不直观.这毕竟不是SQL,它应该遵循正常的OO范例. (7认同)
  • 无论如何,调用函数的顺序应该与最终结果无关. (6认同)
  • 文档确认订单无关紧要:[link](http://docs.mongodb.org/manual/core/read/#combine-cursor-methods) (6认同)
  • 这不应该被接受作为答案,因为它没有按照OP特别要求的那样行事:'得到最后N个记录'和'结果从最近到最近排序,而不是反过来'.此解决方案将从尾部读取N条记录,但由于初始订购操作,它将失去升序,这意味着您需要将结果重新排序为自然:1个订单 (4认同)
  • 一旦你做了``db.foo.find().sort({$ natural:-1}).limit(50);``,你就会以递减的方式得到最后50个条目.我们如何以最佳方式将订单更改为升序? (3认同)
  • 在2013年回答仍然是最新的 (2认同)
  • @Justin Jenkins - 当你有一个包含大量记录的表时,这在性能方面非常糟糕。 (2认同)
  • 不应该依赖自然顺序;如果您正在使用副本集(应该使用副本集),则不同的节点很可能在磁盘上以不同的顺序存储了相同的文档。 (2认同)
  • 自动创建的_id中的date部分是_id的一部分,不能100%准确地用于按日期排序。仅当您从未有超过1次写入/秒https://docs.mongodb.com/manual/reference/method/ObjectId/ (2认同)

Tra*_*lio 107

最后ñ添加的记录,最近少到最近,可以看到与此查询:

db.collection.find().skip(db.collection.count() - N)
Run Code Online (Sandbox Code Playgroud)

如果你想以相反的顺序:

db.collection.find().sort({ $natural: -1 }).limit(N)
Run Code Online (Sandbox Code Playgroud)

如果您安装Mongo-Hacker,您还可以使用:

db.collection.find().reverse().limit(N)
Run Code Online (Sandbox Code Playgroud)

如果您厌倦了编写这些命令,您可以在〜/ .mongorc.js中创建自定义函数.例如

function last(N) {
    return db.collection.find().skip(db.collection.count() - N);
}
Run Code Online (Sandbox Code Playgroud)

然后从mongo shell中输入 last(N)

  • 不应依赖自然秩序;如果您使用副本集(并且您应该使用副本集),则不同的节点很可能将相同的文档以不同的顺序存储在磁盘上。 (3认同)
  • `db.collection.find().reverse().limit(1)` 给我错误 `...没有反向方法` (2认同)

小智 15

 db.collection.find().sort({$natural: -1 }).limit(5)
Run Code Online (Sandbox Code Playgroud)


小智 13

为了获得最后N条记录,您可以执行以下查询:

db.yourcollectionname.find({$query: {}, $orderby: {$natural : -1}}).limit(yournumber)
Run Code Online (Sandbox Code Playgroud)

如果你只想要最后一条记录:

db.yourcollectionname.findOne({$query: {}, $orderby: {$natural : -1}})
Run Code Online (Sandbox Code Playgroud)

注意:您可以使用集合中的一列来代替$ natural.


lau*_*108 12

@陈斌,

您可以对集合中文档子集的最新 n 个条目使用聚合。这是一个没有分组的简化示例(在这种情况下,您将在第 4 阶段和第 5 阶段之间进行)。

这将返回最新的 20 个条目(基于名为“时间戳”的字段),按升序排列。然后它将每个文档 _id、时间戳和whatever_field_you_want_to_show 投影到结果中。

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)
}
Run Code Online (Sandbox Code Playgroud)

所以,结果看起来像:

{ 
    "_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
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。


Joã*_*ero 11

排序、跳过等操作可能会很慢,具体取决于您的集合的大小。

如果您的集合按某些标准编制索引,则会获得更好的性能;然后你可以使用 min() 游标:

首先,索引你的集合db.collectionName.setIndex( yourIndex ) 你可以使用升序或降序,这很酷,因为你总是想要“N个最后项目”......所以如果你按降序索引它与获取“前N个项目”相同.

然后找到集合的第一项,并使用其索引字段值作为搜索中的最小条件,例如:

db.collectionName.find().min(minCriteria).hint(yourIndex).limit(N)
Run Code Online (Sandbox Code Playgroud)

这是 min() 游标的参考:https : //docs.mongodb.com/manual/reference/method/cursor.min/

  • 唯一考虑性能的答案,很好的补充:) (4认同)
  • 显然,您可以忘记最小值并使用: `db.collectionName.find().hint(yourIndex).limit(N)` 如果索引按降序排列,您将获得 N 个最小值。 (2认同)

pkp*_*pkp 6

您可以使用sort(),limit(),skip()拿到最后N个记录开始从任何跳过值

db.collections.find().sort(key:value).limit(int value).skip(some int value);
Run Code Online (Sandbox Code Playgroud)


小智 5

您不能根据集合的大小"跳过",因为它不会考虑查询条件.

正确的解决方案是从所需的终点进行排序,限制结果集的大小,然后根据需要调整结果的顺序.

这是一个基于真实世界代码的例子.

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
        });
    }
});
Run Code Online (Sandbox Code Playgroud)


bel*_*ola 5

您可以尝试以下方法:

使用以下命令获取集合中的记录总数

db.dbcollection.count() 
Run Code Online (Sandbox Code Playgroud)

然后使用跳过:

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()
Run Code Online (Sandbox Code Playgroud)