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


523

我找不到任何记录在案的文件。默认情况下,find()操作将从头开始获取记录。如何获取mongodb中的最后N条记录?

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


7
@Haim,请具体回答,网页的哪一部分解决了我的问题?
陈彬2010年

嗨@BinChen,我最近遇到了同样的问题,解决了吗?
汉顿2015年

Answers:


736

如果我理解您的问题,则需要按升序排序。

假设您有一些名为“ x”的id或日期字段,则可以...

。分类()


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

1将按升序排序(最旧到最新)和-1将降序排序(从最新到最旧的)。

如果您使用自动创建的_id字段,则该字段中嵌入了一个日期...因此您可以使用该日期排序...

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

这将返回从最旧到最新的所有文档。

自然秩序


您还可以使用上述自然顺序 ...

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

同样,根据需要的顺序使用1-1

使用.limit()


最后,优良作法是在进行这种广泛开放的查询时添加一个限制,这样您就可以...

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

要么

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

11
@MortezaM。我很确定您混合了查询顺序...您的sort()应该最后运行,而不是首先运行(很像SQL ORDER BY) .find({})。skip(1).limit( 50).sort({“ date”:-1})
贾斯汀·詹金斯

6
无论是什么,调用函数的顺序都应与最终结果无关。
Morteza Milani 2012年

7
@MortezaM。当然顺序很重要。item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;没有命令,结果将是什么???我同意您的看法,这种颠倒的顺序并不直观。毕竟这不是SQL,它应该遵循正常的OO范式。
RickyA

37
但是顺序并不重要。您所要做的就是尝试一下,看看没有。所有这些都在游标上被调用并传递给服务器,因此服务器限制了排序结果(前N个),因为其他任何事情都没有意义。
Asya Kamsky

9
文件确认顺序无关紧要:连结
JohnnyHK 2013年

120

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

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

如果要以相反的顺序进行操作:

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

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

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

如果您不厌其烦地一直编写这些命令,则可以在〜/ .mongorc.js中创建自定义函数。例如

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

然后从mongo shell键入 last(N)


1
db.collection.find().reverse().limit(1)给我错误... has no method reverse
fish鱼2014年

@Catfish你是对的,我只是注意到[Mongo-Hacker](tylerbrock.github.com/mongo-hacker)添加了reverse(),我将更新我的答案。谢谢。
Trasplazio Garzuglio 2014年

1
db.getCollection('COLLECTION_NAME')。find()。skip(db.getCollection('COLLECTION_NAME')。count()-N)非常适合我:)
Spl2nky

这应该是问题的答案,而不是贾斯汀·詹金斯的答案。
贾迪尔·德·阿玛斯

自然顺序应该不会被依靠; 如果您正在使用副本集(应该使用副本集),则不同的节点很可能在磁盘上以不同的顺序存储了相同的文档。
文斯·鲍德伦

14

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

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

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

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

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


这对我有用db.yourcollectionname.findOne({$ query:{},$ orderby:{$ natural:-1}})。我认为答案中缺少最后的parathensis
Ajay

自然顺序应该不会被依靠; 如果您正在使用副本集(应该使用副本集),则不同的节点很可能在磁盘上以不同的顺序存储了相同的文档。
文斯·鲍德伦

6

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

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

6

您可以尝试以下方法:

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

db.dbcollection.count() 

然后使用跳过:

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()

5

在“查询:排序和自然顺序”下查看,http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order 以及“游标方法”下的sort()在 http://www.mongodb.org/display下/ DOCS /高级+查询


1
谢谢您的答复,我们已经结束了,但是我想将记录从最近到最近的顺序重新整理,这可能吗?
陈彬2010年

自然顺序应该不会被依靠; 如果您正在使用副本集(应该使用副本集),则不同的节点很可能在磁盘上以不同的顺序存储了相同的文档。
文斯·鲍德伦

如果要获取最新记录,则必须依赖文档中的日期字段。
文斯·鲍德伦

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

不错的解决方法!能够在查询级别执行相同操作会很好。有点像var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N)
inwpitrust 2015年

4

@ bin-chen,

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

这将返回最新的20个条目(基于称为“时间戳记”的字段),并按升序排序。然后,它将每个文档_id,时间戳和what_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)
}

因此,结果将类似于:

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

希望这可以帮助。


1
谢谢@ lauri108!在所有有关此问题和相关问题的答案中,这是“如何获得最后N个DOCS”的唯一可行且可靠的解决方案。而且足够简单,只需一个查询即可完成。任务完成。
randomsock

@randomsock,如果您喜欢,请投票:)
lauri108

4

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

如果您按某些条件对集合进行索引,则可以实现更好的性能;然后可以使用min()光标:

首先,db.collectionName.setIndex( yourIndex ) 使用集合进行索引您可以使用升序或降序,这很酷,因为您始终希望“ N个最后一项” ...因此,如果按降序进行索引与获取“前N个项”相同。

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

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

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


仅考虑性能的答案,非常棒:)
zardilior

这个答案能保证订单吗?
zardilior

是的,它保证的基础上,你的指数
若昂·奥特罗

显然,您可以忘记最小值并使用: db.collectionName.find().hint(yourIndex).limit(N) 如果索引按降序排列,则会得到N个最小值。
haltux


0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

根据mongoDB文档

您可以指定{$ natural:1}强制查询执行前向集合扫描。

您也可以指定{$ natural:-1}强制查询执行反向集合扫描。


0

使用$ slice运算符限制数组元素

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

地理位置是数据数组,从中我们得到最后5条记录。


-5

最后一个功能应该是sort,不是limit

例:

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

2
这似乎不正确。为什么会sortlimit
Acumenus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.