在MongoDB中批量查找FindAndModify的解决方案

ame*_*til 15 mongodb nosql

我的用例如下 - 我在mongoDB中有一组文件,我必须发送这些文件进行分析.文件格式如下 -

{_id:ObjectId("517e769164702dacea7c40d8"),日期:"1359911127494",状态:"可用",other_fields ...}

我有一个读取器进程,它选择前100个具有状态的文档:日期排序并使用状态修改它们:处理.ReaderProcess发送文档进行分析.分析完成后,状态将更改为已处理.

目前,读者进程先取排序100个文件日期,然后更新状态处理为一个循环的每个文档.对于这种情况,有没有更好/更有效的解决方案?

此外,在未来的可扩展性方面,我们可能会使用多个读取器进程.在这种情况下,我希望一个阅读器进程选择的100个文档不会被另一个阅读器进程选中.但是现在提取和更新是单独的查询,因此很多读者进程很可能选择相同的文档.

批量findAndModify(有限制)将解决所有这些问题.但不幸的是,它尚未在MongoDB中提供.有没有解决这个问题的方法?

Rem*_*iet 13

如你所说,目前没有干净的方法来做你想要的.对于像您需要的操作,此时的最佳方法是:

  1. Reader选择具有适当限制和排序的X文档
  2. Reader标记1)返回的文件,带有自己独特的读者ID(e.g. update({_id:{$in:[<result set ids>]}, state:"available", $isolated:1}, {$set:{readerId:<your reader's ID>, state:"processing"}}, false, true))
  3. Reader选择标记为处理的所有文档,并使用它自己的读者ID.此时,保证您可以独占访问生成的文档集.
  4. 提供3)的结果集供您处理.

请注意,这甚至可以在高度并发的情况下工作,因为读者永远不会保留其他读者尚未保留的文档(请注意,第2步只能保留当前可用的文档,并且写入是原子的).如果您希望能够超时预订(例如,读者可能崩溃/失败的情况),我会添加一个带预约时间的时间戳.

编辑:更多细节:

如果写入时间相对较长,则所有写入操作偶尔会产生挂起操作.这意味着步骤2)可能看不到步骤1)标记的所有文档,除非您采取以下步骤:

  • 使用适当的"w"(写入关注)值,表示1或更高.这将确保调用写入操作的连接将等待它完成而不管它是否产生.
  • 确保在同一连接上执行步骤2中的读取(仅与启用了slaveOk的读取的复制集相关)或线程,以确保它们是顺序的.前者可以在大多数驱动程序中使用"requestStart"和"requestDone"方法或类似方法(此处为 Java文档)完成.
    • 将$ isolated标志添加到多重更新中,以确保它不能与其他写操作交错.

另请参阅有关原子性/隔离的讨论的注释.我错误地假设多次更新被隔离.它们不是,或者至少不是默认的.