【问题标题】:Does MongoDB support Upsert to an Array FieldMongoDB 是否支持对数组字段进行 Upsert
【发布时间】:2013-01-31 05:19:09
【问题描述】:

我的文档结构如下:

{
    "_id" : 1000001,
    "ListMembers" : [
            {
                    "MemberID" : 1000,
                    "Notes" : "Test Notes for 1000"
            },
            {
                    "MemberID" : 1001,
                    "Notes" : "Test Notes for 1002"
            }
    ]

}

应用程序生成一个唯一 ID。 我需要实现以下目标:

  1. 如果文档不存在,则使用数组插入一个新文档 场地。
  2. 如果文档存在于集合和成员记录中 存在于数组中然后更新成员注释
  3. 如果文档在集合中存在且成员记录不存在 存在于数组中,然后在数组中插入成员记录。

这里 #1 和 #2 工作正常,但 {upsert:true} 选项不适用于上面的 #3;如果文档存在但成员记录不存在,它会尝试插入具有相同 ID 的新文档,这显然会给我一个重复键错误。 MongoDB 在这种情况下是否支持 UPSERT 操作,或者我是否需要检查文档是否存在,然后对 #1 和 ($pull 和 $push) 执行 INSERT 以在数组字段上实现 #2 和 #3。

【问题讨论】:

  • 我今天遇到了这个问题,发现先执行 $pull 然后 $push 适用于所有三个条件。

标签: mongodb


【解决方案1】:

目前不支持,因为 $ positional operator 不支持更新插入:

不要将位置运算符 $ 用于 upsert 操作,因为插入将使用 $ 作为插入文档中的字段名称。

位置运算符需要更新成员记录的注释,但不适用于 upsert。

我建议的逻辑是执行更新查询以覆盖 #2 和 #3 - 我会确保 writeconcern 为 1 - 所以它返回更新的文档数。如果它返回 none,则插入 $push 项目到 ListMembers - 这包括 #1*

*这里有一个潜在的竞争条件 - 对于额外的分数,你应该确保当你尝试执行 $push 时,它会检查它 不匹配 ListMembers 方面并设置写关注。如果$push 操作返回 0 - 这意味着文档在第一个操作和这个操作之间进行了更新,因此您现在可以继续使用 $update,因为现在有一个匹配项,它将更新它。

【讨论】:

  • 无法像这样解决竞争条件问题,因为 $push 创建了一个副本而不是返回 0。如果“Notes”字段不存在,我可以使用 $addToSet;这也会创建一个重复项,因为它会查看所有字段(即 MemberID 和 Notes),并且显然在竞争条件下创建的 Notes 会有所不同,这将阻止它将在竞争条件下创建的记录视为重复。所以即使 $addToSet 最终也会创建另一条记录。
  • 在执行 $push 时,您必须确保您没有执行 upsert 并且查询部分不匹配 - 这将停止重复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2019-01-03
相关资源
最近更新 更多