2016-08-02 22 views
0

我有一个应用程序不断地将文档插入到MongoDB集合中。MongoDB - 反映插入顺序的字段

我正在寻找一种方法来查询其插入顺序后的文档。

候选人我想用:

  • _id
  • 创建日期域
  • 序列号(自动递增)

_id领域是不是一个好候选人作为文档说。创建日期字段可能是一个很好的候选字段,但时钟可能不同步的事实可能会破坏订单。关于序列号,文件提出了两种方法:计数器和乐观循环。由于文档D1可能会插入另一个文档D2,即使D1.seq < D2.seq,计数器方法也不能保证插入顺序。例如,如果D1获取序列号5,则D2获取序列号6,然后插入D2,然后插入D1。乐观循环的方法是疯狂的情况下,沉重的插入环境。

有没有另一种方法?


编辑:

使用计数器的方法是有问题的。考虑以下情况。我有一个应用程序A,它不断地将文档插入到一个集合中。我还有另一个应用程序B,它不断地轮询来自同一个集合的文档。应用程序A是多线程的。两个线程T1T2分别将插入文档D1D2。在插入过程中,应用程序B要求提供更多文档。假设以下的操作顺序:

  1. 主题A-T1抓住下一个序列号N
  2. 主题A-T2抓住下一个序列号N+1
  3. 主题A-T2插入D2
  4. 应用B询问与seq >= N文件(假设最后处理的文件有seq号N-1)并且收到D2D1还没有恩插入尚)
  5. 主题A-T1插入D1
  6. 应用B询问与seq >= N+2文件(自上次处理的文档具有序列号N+1

在这种情况下,D1将永远不会被处理。

+0

如果我正确地理解了你,你需要一种方式来知道文件创建和保存的顺序。我建议你自己生成_id。例如,当服务器启动时,你插入最后一个_id(或最大的一个,就像1505)。然后你只需在每个文件上增加计数器。你很好走。即使某些文档无法保存,您可以将其保存到某个JSON文件并稍后重新保存。当时会生成_id,您将拥有订单系统。希望这可以帮助。 –

+0

我不明白你的方法与问题中的第三种方法不同。 –

+0

是的,这里只有更多的单词。 –

回答

0

如果您希望每秒插入数十次,乐观锁定是唯一的方法。

否则时钟同步可能是一个更好的主意。

考虑到柜台,你能否详细说明它是如何影响你的申请的,如果D1D2之后持续存在,你是否保证获得顺序号码的顺序? MongoDB本身的“插入”操作有多个阶段,您可以尽可能深入地依赖日志记录。

编辑

你可以考虑tailable cursor作为应用B一个选择吗?它不直接回答这个问题,但它可能解决问题背后的问题。

EDIT 2

,那么你可能需要使用任何种类的消息队列的应用程序之间进行通信,就像在图像上。这可能是一种矫枉过正,但如果你确信乐观锁定是一个瓶颈,那么它可能是可以接受的。

在下面的图片:

  1. 应用A以任意顺序插入文档和检索蒙戈客户端唯一对象ID。

  2. 应用A发送的objectID队列以任意顺序

  3. 应用B获取下一步的objectID从队列

  4. 应用通过ID从数据库B取文件

enter image description here

编辑3

最后,你可以考虑到状态添加到文档和乐观锁转移到应用B

  1. 检索和未处理的文件的objectID:db.collection.findOne({status: null}, {})

  2. 将其状态更改为'处理'

    db.collection.findAndModify({ 
        query: { _id: objectId, status: null }, 
        update: { $set: { status: 'processing' }} 
    }) 
    

    ,如果返回null - 该文件正在由B另一个实例处理,所以返回步骤1

  3. 过程中的文档并更新其状态为“完成”:

    db.collection.findAndModify({ 
        query: { _id: objectId, status: 'processing' }, 
        update: { $set: { status: 'done' }} 
    }) 
    

使用这种方法,你完全不关心确切的序列。如果您想按顺序处理文档,您可以添加时间戳或在ObjectId上继续对第1步中的文档进行排序。当然,这可能不是确切的顺序,但您不需要它来保证处理所有文档。

+0

请参阅我的编辑 –

+0

关于您对乐观循环的评论,我认为它是相反的 - 即乐观循环效率低下,并发插入很多,因为它可能会循环多次,才能插入文档而不会出现重复错误。 –

+0

乐观锁vs时间戳的原因是,当你以毫秒为单位计算时,NTP可能不够,但我看到你指向执行。尽量避免过早优化,直到你**证明**这是一个问题。 关于您的编辑 - 应用程序“B”如何知道序列号?它完全属于应用程序'A'域。 'B'只能要求返回最新的1000个文件,按序号排序。像“比时间戳更早”的任何其他过滤器也可以,假设您为过滤添加了时间戳。序列号仅用于排序。 –