如何独立更新数百万文档?PHP+Mongo


How to update millions of documents independently? PHP + Mongo

我有一个非常大的聚合,它为每个用户(在集合中)汇总了一些活动。此聚合返回数百万个结果(每个用户活动)。使用这种格式:

 Array ( [_id] => Array ( [user] =>
      MongoId Object ( [$id] => 52050d48e654f6342c002d42 )
        [send] => 1
        [open] => 1
        [click] => 2 )

现在我需要做一些事情:

  • 使用这些结果更新用户(增加现有值)
  • 更新后计算每个用户的平均值(打开/发送)
  • 将每个平均值与一个数字进行比较,并根据结果为用户添加一个标志

在不循环使用聚合结果并一次更新每个结果的情况下,如何使用聚合结果更新用户?

如果我理解正确,您分享的示例结果是:

{
  user: ObjectId("52050d48e654f6342c002d42"),
  send: 1,
  open: 1,
  click: 2
}

将需要执行以下操作:

  • 将该用户的sendopen字段分别增加1
  • 将增量后的open/send比率(未存储)与某个值进行比较,并根据比较结果在用户文档上设置布尔标志

充其量,我认为您可以预先聚合将接收类似更新的用户,并发布多文档更新,其中_id是值数组中的$in;然而,这仍然需要MongoDB单独查询每个用户。$in数组参数的大小是有限制的,但此策略的主要好处是,您将在驱动程序和服务器之间发送更少的操作,并且您将收到单个GLE(即获取最后一个错误)响应。

open/send比率的计算将更加棘手,因为这将需要从所有文档中获取这些字段。在更新步骤之后,您可能能够针对用户集合发布第二个聚合,并在两个字段上使用$divide来计算该值。然后,您可以在比较运算符中使用商和其他值。这将允许您创建一个仅包含用户ID和布尔值的聚合结果。从那时起,您仍然需要从驱动程序发出更多的更新语句,尽管将这些语句分组为多文档更新会简单得多,因为标志字段只有两个可能的值。

我绝对建议将标志字段设置为始终存在的布尔值,因为这将使您可以更改其值,而不用担心创建新字段,也不用担心在文档超出其分配空间时无意中需要在磁盘上移动文档。您应该尽可能地进行就地更新。

最后,PHP驱动程序的另一个选项是更新操作的写入问题。通过使用零写问题,您可能会获得一些性能(以牺牲错误检查为代价),因为这将允许您尽可能快地向MongoDB发送更新,而无需等待错误响应。