我正在创建一个java程序来处理MongoDB的Collection作为队列。因此,当我出列队列时,我想要首先插入的文档。
为此,我有一个名为created的字段,它表示文档创建的时间戳,我最初的想法是使用聚合$ min来使用创建的字段查找最小的文档。
然而,我想到为什么不使用没有任何参数的findOne()。它将始终返回集合中的第一个文档。
所以我的问题是我应该这样做吗?使用findOne()并从Mongo队列中取出第一条记录是一种好方法吗?如果我这样做会有什么缺点。
PS:创建Mongo Queue程序是为了在First Come First Serve的基础上提供设备的请求。但由于执行请求需要一些时间,因此设备在处理请求时无法接受另一个请求。因此,为了防止丢弃一个请求,我使用队列逐个处理请求。
答案 0 :(得分:4)
有趣的是,此处有多少人注释错误,但您是对的,原始.findOne()
带有空白查询或.findOne({})
将返回集合中的第一个文档,即"具有最低_id
值"。
理想情况下,对于队列处理系统,您希望在执行此操作的同时删除文档。为此,Java API支持.findAndRemove()
方法:
DBCollection data = mongoOperation.getCollection("data");
DBObject removed = data.findAndRemove(new DBObject());
因此,将按照描述返回集合中的第一个文档,并且"删除"它来自集合,所以没有其他操作可以找到它。
您可以拨打.findAndModify()
并自行设置所有选项,但如果你所有的选项都是"最早的文件,那么#34}这是_id
所保证的,这就是你想要的。
答案 1 :(得分:2)
findOne返回natural order中的元素。这与插入顺序不一定相同。它是文档在磁盘中出现的顺序。可能看起来它是按插入顺序检索的,但是删除和插入后,您将开始看到文档无序显示。
保证元素始终以插入顺序出现的方法之一是使用capped collections。如果您的应用程序不受其限制的影响,则可能是使用上限集合实现队列的最简单方法。
上限集合也可以与tailable cursor一起使用,以便在没有可供处理的项目的情况下,从队列中检索项目的逻辑可以继续等待项目。
更新:如果您不能使用上限集合,则必须按_id排序结果,如果它是ObjectId,或者在集合中保留基于时间戳的字段,并按该字段对结果进行排序。
答案 2 :(得分:0)
FindOne使用幕后存在的内部MongoDB bTree中的$natural
顺序返回。
默认情况下,该功能不会按_id
排序,也不会选择最低_id
。
如果您发现它会定期返回最低_id
,那么这是因为$natural
索引中的文档定位。
获取集合的第一个文档和排序集的第一个文档是两个完全不同的东西。
如果您想使用findAndModify
从文件堆中抓取文档,我个人会建议使用乐观锁定,那么您需要使用:
findAndModify({
sort: {_id: -1},
remove: true
})
我不赞扬这种方法的原因是因为该进程崩溃或服务器在分布式工作集中发生故障,然后您丢失了该数据点。相反,您需要一个临时(乐观类型)锁,可以在未正确处理的情况下释放。