【问题标题】:Is there any way to atomically update two collections in MongoDB?有什么方法可以自动更新 MongoDB 中的两个集合?
【发布时间】:2011-05-22 19:26:41
【问题描述】:

我有一组消息:

{
    messageid: ObjectId
    userid: ObjectId
    message: string
    isread: true|false
}

以及每个用户的消息计数集合:

{
    userid: ObjectId
    total: int
    unread: int
}

当我从“messages”集合中删除一条消息时,我还需要减少“counts”集合中的“total”,并有条件地(如果“messages.isread”== false)减少“未读”字段。

为此,我需要先检索消息,检查其“isread”字段,然后更新计数。在这些操作之间,邮件可能会被标记为已读,然后我会错误地减少“未读”计数。

有没有办法根据一次性收集的结果有条件地更改一个集合中的某些内容?

【问题讨论】:

    标签: concurrency mongodb


    【解决方案1】:

    这里有很多答案,但我想在这里填写所有空白:

    有没有办法在 MongoDB 中自动更新两个集合?

    没有。两个集合的原子更新实际上是一个事务。 MongoDB 不支持跨集合甚至是集合内的事务。

    MongoDB 提供several modifiers,它们在单个文档上是原子的。因此,您可以一次增加几个不同的变量 ($inc)。尽管这里有一些限制,但您不能对单个属性执行两种不同的操作。

    有没有办法根据一次性收集的结果有条件地更改一个集合中的某些内容?

    这里有一些关于atomic updates 的文档。但是,您真正需要的是一个队列和某种形式的two-phase commit,或者您需要触发器。

    触发器有not yet been implemented,所以在你的情况下它不是一个真正的选择。

    邮件可能会在这些操作之间被标记为已读,然后我会错误地减少“未读”计数。

    此时,您有几种不同的策略可以使其行为具有某种程度的一致性。坦率地说,根据您的描述,您可能想研究建立一个简单的队列来更新您的总数。

    【讨论】:

    • 我同意在撰写此答案时触发器可能不可用,但对所有登陆这里的人来说,现在有一个选项可用,查看 MongoDB Stitch (docs.mongodb.com/stitch/#stitch) 和 Stitch 触发器 (@ 987654326@)..
    【解决方案2】:

    您不能同时从两个集合中删除文档。您可以做的是使用 findAndModify() 删除文档,以便在删除之前获得其确切状态。这将解决您的未读计数问题。

    【讨论】:

      【解决方案3】:

      不,很遗憾,这是不可能的。 MongoDB 仅支持单个文档范围内的atomic operations。无法跨多个文档执行事务操作,即使它们在同一个集合中。

      【讨论】:

        【解决方案4】:

        MongoDB 非常快,因此如果您的站点负载不高,您可以简单地重新计算消息总数和每次请求读取的消息总数。只在 isread 上放一个索引。计数似乎非常快,即使在大量数据上也是如此。

        事实上,您的总数和未读字段只是缓存。你真的需要吗?

        这里有一个关于类似问题的问题:MongoDB: Calling Count() vs tracking counts in a collection

        【讨论】:

        • 这也是我的问题 :) 我的网站的负载会比较高,而且我不想每次需要时都重新计算统计数据,所以我使用了那个计数器集合。跨度>
        • 即使没有分析,我可以说 cursor.count() 总是比只检索一个数字慢得多,尤其是在具有数亿条记录的集合上。
        • 有了字段索引,我认为可以在不扫描集合中的每个文档的情况下进行计数,只需查看索引即可。看看这个:mongodb.org/display/DOCS/… 所以 count() 与读取文档中的数字基本相同,集合的大小无关紧要。
        • @Maxence - 坦率地说,我不认为你是对的 - 调用 count() 仍在进行实时聚合; index 只是通过将所有需要计算的块对齐来帮助它加快速度。
        • 你是对的。这篇 groups.google.com/group/mongodb-user/browse_thread/thread/… 的帖子表明 MongoDB 会扫描所有行以获取计数。我以为可以从索引中检索它,但事实并非如此。
        【解决方案5】:

        您可以使用 sql 中的触发器来执行此操作。但是在mongo中,没有触发器。

        您可以对其中一个文档执行操作,并通过设置 SafeMode.True 来检查该操作上的 LastErrorMessage

        如果没有错误则更新第二个集合。

        目前没有办法以原子方式执行此操作。

        如果有,我会在我的项目中使用。我也需要那个功能。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-22
          • 1970-01-01
          相关资源
          最近更新 更多