我有一个不断将文档插入MongoDB集合的应用程序。
我正在寻找一种在插入订单后查询文档的方法。
我想要使用的候选人:
_id
字段正如文档所说,_id
字段不是一个好的候选字段。创建日期字段可能是一个很好的候选者,但是时钟可能不同步这一事实可能会破坏顺序。关于序列号,文档提出了两种方法:计数器和乐观循环。计数器方法不保证插入顺序,因为即使D1
,也可以在另一个文档D2
之后插入文档D1.seq < D2.seq
。例如,如果D1
占用序号5,则D2
占用序列号6,然后插入D2
,然后插入D1
。在插入环境较重的情况下,乐观循环方法很疯狂。
还有其他方法吗?
修改
使用计数器的方法存在问题。请考虑以下情形。我有一个应用程序A
,它不断地将文档插入到集合中。我还有另一个应用程序B
,它不断轮询来自同一集合的文档。应用程序A
是多线程的。两个帖子T1
和T2
即将分别插入文档D1
和D2
。在插入过程中,应用程序B
要求提供更多文档。假设以下操作顺序:
A-T1
占用下一个序列号N
A-T2
占用下一个序列号N+1
A-T2
插入D2
B
要求包含seq >= N
的文档(假设处理的最后一个文档的序号为N-1
)并收到D2
(D1
尚未插入)A-T1
插入D1
B
要求提供seq >= N+2
的文档(因为上次处理的文档的序号为N+1
)在这种情况下,永远不会处理D1
。
答案 0 :(得分:0)
如果您希望每秒数十个插入,乐观锁是唯一的方法。
否则时钟同步可能是个更好的主意。
考虑到计数器,如果在D1
之后保留D2
,您是否可以详细说明它对您的应用程序的影响,因为您保证获取序列号的顺序? &#34;插入&#34; mongodb本身的操作有多个阶段,你可以像依赖日记一样深入。
修改强>
您会将tailable cursor视为申请B
的选项吗?它没有直接回答这个问题,但它可以解决问题背后的问题。
编辑2
然后,您可能需要使用任何类型的消息队列在应用程序之间进行通信,例如在图像上。这可能是一种矫枉过正,但如果您确定乐观锁定是一个瓶颈,那么它可能是可以接受的。
在下图中:
应用程序A
以任意顺序插入文档,并从mongo客户端检索唯一对象ID。
应用程序A
以任意顺序将objectID发送到队列
应用程序B
从队列中获取下一个objectID
应用程序B
按ID从数据库中获取文档
编辑3
最后,您可以考虑向文档添加状态并将乐观锁转换为应用B
:
检索未处理文档的对象ID:db.collection.findOne({status: null}, {})
将其状态更改为&#39;处理&#39;
db.collection.findAndModify({
query: { _id: objectId, status: null },
update: { $set: { status: 'processing' }}
})
如果它返回null - 文档正由另一个B
实例处理,所以返回步骤1
处理文档并将其状态更新为“完成”
db.collection.findAndModify({
query: { _id: objectId, status: 'processing' },
update: { $set: { status: 'done' }}
})
通过这种方法,您根本不关心确切的顺序。如果要按顺序处理文档,可以在ObjectId上添加时间戳或中继以在步骤1中对文档进行排序。它当然可能不是确切的顺序,但您并不需要它来保证所有文档都得到处理。