从MongoDB集合中获取最新记录

140

我想知道如何获取集合中的最新记录。如何实现?

注意:我知道下面的命令行查询可以工作:

1. db.test.find().sort({"idate":-1}).limit(1).forEach(printjson);
2. db.test.find().skip(db.test.count()-1).forEach(printjson)

其中idate已添加了时间戳。

问题在于,集合越大,获取数据的时间就越长,而我的“test”集合非常非常庞大。我需要一个具有恒定时间响应的查询。

如果有更好的mongodb命令行查询,请告诉我。

10个回答

186

这是对之前答案的重新概括,但更有可能在不同的mongodb版本上起作用。

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

20
db.collection.find().limit(1).sort({$natural:-1}).pretty() 如果你想让它看起来漂亮 - Anthony
那么,这个命令与以下命令有何不同:db.collection.find().sort({$natural:-1}).limit(1).pretty() - Leo
@Digits 如果我们在最后加上限制,会对性能产生什么影响?当你将输出限制为一个文档并且必须是集合中的顶部文档时,最后一条记录如何获取? - kailash yogeshwar
好的回答。我尝试了这样做: db.collection("集合名称").find({}, {limit: 1}).sort({$natural: -1}) - Abdul Alim Shakir
1
对于使用AWS DocDB的任何人:在docdb服务器上,查询失败,错误代码为303,错误消息为“不支持选项$natural”。希望这个功能很快就会推出。 - Marc
在Python/PyMongo中:docs = dbCollectionQuotes.find({}).limit(1).sort([('$natural', pymongo.DESCENDING)]),它返回一个游标,因此即使只有一个,您也必须进行循环。 - NealWalters

61

这将为您提供一个集合的最后文档

db.collectionName.findOne({}, {sort:{$natural:-1}})

$natural:-1 表示记录排序的顺序与插入顺序相反。

编辑: 对于所有的反对者,上述是 Mongoose 语法,mongo CLI 语法为: db.collectionName.find({}).sort({$natural:-1}).limit(1)


7
您的语法似乎有误,按照您的写法我无法让它正常工作。下面这段代码是可以正常工作的: 'db.punchdeck.findOne( {$query:{}, $orderby:{$natural:-1}} )'。 - Dave Lowerre
2
不确定为什么会有这么多负评 - 这段代码在我这里完美运行,而且速度很快。 - dark_ruby
3
@dark_ruby,您的查询返回错误"$err": "无法规范化查询:BadValue 不支持的投影选项:sort:{ $natural: -1.0 }"。 - Roman Podlinov

25

从 MongoDB 集合获取最后一项的另一种方法(不用在意示例):

> db.collection.find().sort({'_id':-1}).limit(1)

正交投影

> db.Sports.find()
{ "_id" : ObjectId("5bfb5f82dea65504b456ab12"), "Type" : "NFL", "Head" : "Patriots Won SuperBowl 2017", "Body" : "Again, the Pats won the Super Bowl." }
{ "_id" : ObjectId("5bfb6011dea65504b456ab13"), "Type" : "World Cup 2018", "Head" : "Brazil Qualified for Round of 16", "Body" : "The Brazilians are happy today, due to the qualification of the Brazilian Team for the Round of 16 for the World Cup 2018." }
{ "_id" : ObjectId("5bfb60b1dea65504b456ab14"), "Type" : "F1", "Head" : "Ferrari Lost Championship", "Body" : "By two positions, Ferrari loses the F1 Championship, leaving the Italians in tears." }

排序投影(按_id倒序)

> db.Sports.find().sort({'_id':-1})
{ "_id" : ObjectId("5bfb60b1dea65504b456ab14"), "Type" : "F1", "Head" : "Ferrari Lost Championship", "Body" : "By two positions, Ferrari loses the F1 Championship, leaving the Italians in tears." }
{ "_id" : ObjectId("5bfb6011dea65504b456ab13"), "Type" : "World Cup 2018", "Head" : "Brazil Qualified for Round of 16", "Body" : "The Brazilians are happy today, due to the qualification of the Brazilian Team for the Round of 16 for the World Cup 2018." }
{ "_id" : ObjectId("5bfb5f82dea65504b456ab12"), "Type" : "NFL", "Head" : "Patriots Won SuperBowl 2018", "Body" : "Again, the Pats won the Super Bowl" }

sort({'_id':-1})定义了一个基于文档_id降序排列的投影。

排序投影(按 _id 反向排序):从集合中获取最新(最后)的文档。

> db.Sports.find().sort({'_id':-1}).limit(1)
{ "_id" : ObjectId("5bfb60b1dea65504b456ab14"), "Type" : "F1", "Head" : "Ferrari Lost Championship", "Body" : "By two positions, Ferrari loses the F1 Championship, leaving the Italians in tears." }

20

我需要一个具有常数时间响应的查询

MongoDB中默认的索引是B树。搜索B树是一个O(logN)的操作,所以即使是find({_id:...})也不能提供常数时间的O(1)响应。

但如果你使用ObjectId作为ID, 也可以按_id进行排序。详情请见这里。当然,这种方式只能保证到上一秒。

你可能需要采用"写两次"的方法。将数据先写入主要集合,再写入一个“最近更新”的集合。没有事务,这不是完美方案,但在“最近更新”集合中只有一项时,它总是快速的。


2
我看到很多noSQL和MongoDB的解决方案都提倡“写两次”,尤其是在数据量变得非常大时。我猜这是常见的做法吗? - Vinny
1
MongoDB不经常刷新到磁盘,也没有事务,因此写入速度变得更快。这里的权衡是,您被鼓励去反规范化数据,这通常会导致多次写入。当然,如果您获得了10倍或100倍的写入吞吐量(我见过),那么2倍或3倍的写入仍然是一个很大的改进。 - Gates VP
在B-Tree中搜索不是O(logN)操作,这只适用于左值小于右值和根节点值的BinarySearchTree,而在BinaryTree中并非如此。对于B-Tree,它仍然是O(N),其中N为节点数。 - user16486258
@NaveenKumar,维基百科的条目字面上将搜索描述为O(log n),在最坏和平均情况下都是如此。这实际上是一个50年历史的算法。你在这里带来了什么新东西吗?https://en.wikipedia.org/wiki/B-tree - Gates VP
@GatesVP,你提供的B-Tree文章和我想象中的不同。这就是为什么会出现这种情况。当你说“B-Tree”时,我以为你是在说“二叉树”。你提供的文章中第一行就写着:“不要将其与二叉树或B+树混淆”。如果它是一个二叉树,那么在其中搜索一个节点肯定是O(N)的。 - user16486258

2

PHP7.1 MongoDB:
$data = $collection->findOne([],['sort' => ['_id' => -1],'projection' => ['_id' => 1]]);

在PHP7.1版本中使用MongoDB,以上代码是从集合中查找符合条件的文档,并按照_id字段倒序排序,只返回_id字段。

1
如果您在文档中使用自动生成的Mongo对象ID,则其中包含时间戳作为前4个字节,可以使用它找到最新插入集合的文档。我知道这是一个老问题,但如果有人仍然在寻找另一种选择,可以参考此方法。
db.collectionName.aggregate(
[{$group: {_id: null, latestDocId: { $max: "$_id"}}}, {$project: {_id: 0, latestDocId: 1}}])

上述查询将返回插入到集合中的最新文档的_id

1

我的解决方案:

db.collection("集合名称").find({}, {limit: 1}).sort({$natural: -1})


1

让Mongo创建ID,它是一个自增的哈希值

mymongo: self._collection.find().sort("_id", -1).limit(1)


1

Mongo CLI语法:

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

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接