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

时间:2013-05-02 09:00:11

标签: mongodb nosql

我的用例如下 - 我在mongoDB中有一组文档,我必须发送它们进行分析。 文件格式如下 -

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

我有一个阅读器流程,它选择状态的前100个文档:可用 date 排序,并使用 status:processing 修改它们。 ReaderProcess发送文档进行分析。分析完成后,状态将更改为已处理

目前读者流程首先获取按 date 排序的100个文档,然后将循环中每个文档的状态更新为处理。对于这种情况,有没有更好/更有效的解决方案?

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

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

1 个答案:

答案 0 :(得分:13)

如你所说,目前没有干净的方法来做你想要的。对于像你需要的那样的操作,目前最好的方法是:

  1. Reader选择具有适当限制和排序的X文档
  2. Reader使用自己唯一的读者ID(e.g. update({_id:{$in:[<result set ids>]}, state:"available", $isolated:1}, {$set:{readerId:<your reader's ID>, state:"processing"}}, false, true)
  3. 标记1)返回的文档
  4. 阅读器选择标记为处理的所有文档,并使用自己的阅读器ID。此时,保证您可以独家访问生成的文档集。
  5. 提供3)的结果集供您处理。
  6. 请注意,这甚至可以在高度并发的情况下工作,因为读者永远不会保留其他读者尚未保留的文档(请注意,第2步只能保留当前可用的文档,并且写入是原子的)。如果您希望能够超时预订(例如读者可能崩溃/失败的情况),我会添加一个预约时间的时间戳。

    编辑:更多详情:

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

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

    另见有关原子性/隔离的讨论的评论。我错误地假设多次更新被隔离。它们不是,或者至少不是默认的。