Mongo 当多个嵌套对象的 ID 存在于列表中时更新它们

Mongo update multiple nested objects when their ID exists in a list

当列表中存在 ID 时,我正在尝试更新嵌套数组中的许多对象。

文档结构如下:

{
    id: p00,
    children: [{
            id: c00,
            value: true
        },
        {
            id: c01,
            value: true
        },
        {
            id: c02,
            value: true
        }
    ]
}

如果 id=p00children.id[c00, c01] 中,我想设置 value=false

这是我的尝试,但它显然正在更新,仅对父记录进行 1 次更新,这意味着只有 c00 会被修改为 false 值。

collection
    .updateMany(and(
        eq("id", "p00"),
        in("children._id", [c00, c01])), 
    combine(
        set("children.$.value", false)
));

这可能吗,还是我需要将子项向上移动以形成更扁平的结构?我不想这样做,因为这会引入它自己的问题。

谢谢!

您可以通过管道更新来完成。

管道更新允许我们使用所有聚合运算符,因此我们可以进行复杂的更新(在您的情况下,也许也可以使用更新运算符,但使用管道很容易)

管道更新需要 >= MongoDB 4.2.

Test code here

查询

  • 匹配 id=p00
  • 映射子数组的每个成员($$c 变量)
    如果 $$c.id 在列表 ["c00","c01"]
    中 然后成员将 $$c{"value" : false} 合并(就像添加键值对)
    否则不要改变 $$c
db.collection.update({
  "id": {
    "$eq": "p00"
  }
},
[
  {
    "$set": {
      "children": {
        "$map": {
          "input": "$children",
          "as": "c",
          "in": {
            "$cond": [
              {
                "$in": [
                  "$$c.id",
                  [
                    "c00",
                    "c01"
                  ]
                ]
              },
              {
                "$mergeObjects": [
                  "$$c",
                  {
                    "value": false
                  }
                ]
              },
              "$$c"
            ]
          }
        }
      }
    }
  }
])

如果您不想使用更新管道(您的更新很简单,也可以使用数组过滤器来完成),并且在 Java 中会像下面这样。

coll.updateOne(new Document().append("id","p00"),
               new Document().append("$set",new Document().append("children.$[item].value",false)),
               new UpdateOptions().arrayFilters(
                 Collections.singletonList( Filters.in("item.id",Arrays.asList("c00","c01")))))