Concurrency 有没有办法在MongoDB中以原子方式更新两个集合?

Concurrency 有没有办法在MongoDB中以原子方式更新两个集合?,concurrency,mongodb,Concurrency,Mongodb,我有一组信息: { messageid: ObjectId userid: ObjectId message: string isread: true|false } 以及每个用户的邮件计数集合: { userid: ObjectId total: int unread: int } 当我从“messages”集合中删除消息时,我还需要减少“counts”集合中的“total”,并有条件地(如果“messages.isread”==fa

我有一组信息:

{
    messageid: ObjectId
    userid: ObjectId
    message: string
    isread: true|false
}
以及每个用户的邮件计数集合:

{
    userid: ObjectId
    total: int
    unread: int
}
当我从“messages”集合中删除消息时,我还需要减少“counts”集合中的“total”,并有条件地(如果“messages.isread”==false)减少“unread”字段

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


有没有一种方法可以根据其他集合的结果一次性有条件地更改一个集合中的某些内容?

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

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

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

目前没有办法用原子的方式来实现这一点


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

不,不幸的是,这是不可能的。MongoDB仅在单个文档的范围内支持。即使多个文档位于同一个集合中,也无法跨多个文档执行事务操作。

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

MongoDB速度非常快,因此如果您的站点负载不高,您只需重新计算邮件总数和每次请求时读取的邮件总数。只在isread上放一个索引。计数似乎非常快,即使在大量数据上也是如此

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


这里有一个关于类似问题的问题:

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

有没有办法在MongoDB中以原子方式更新两个集合

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

MongoDB提供了在单个文档上是原子的。因此,您可以一次递增多个不同的变量(
$inc
)。虽然这里有一些限制,但不能对单个属性执行两个不同的操作

是否有一种方法可以根据一次采集的其他采集结果有条件地更改一个采集中的某些内容

一般来说,这里有一些文件。然而,您真正需要的是队列和某种形式的or触发器

触发器有,所以在您的情况下,它不是一个真正的选项

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


在这一点上,您有两种不同的策略使其具有一定程度的一致性。坦白地说,根据您的描述,您可能想研究构建一个简单的队列来更新您的总数。

这也是我的问题:)我的站点将具有相当高的负载,我不想在每次需要统计数据时都重新计算统计数据,所以我使用计数器集合。即使没有分析,我也可以说cursor.count()将总是比仅检索一个数字慢得多,尤其是在具有数亿条记录的集合上。通过字段上的索引,我认为无需扫描集合中的每个文档,只需查看索引即可完成计数。看看这个:所以count()与读取文档中的数字基本上是一样的,而且集合的大小也无关紧要。@Maxence-坦白地说,我认为你是不对的-调用count()仍在进行实时聚合;索引只是通过将所有需要计算的块对齐在一起来帮助它加快速度。你是对的。本文显示MongoDB扫描所有行以获得计数。我想它可以从索引中检索,但事实并非如此。我同意在撰写此答案时,触发器可能不可用,但对于所有登陆此处的人,现在有一个选项可用,请查看MongoDB Stitch()&Stitch触发器()。。