You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB嵌套数组更新求助:基于条件更新memberOfGroups与roles

MongoDB嵌套数组更新问题及解决方案

我正尝试基于过滤条件更新MongoDB中的嵌套数组,但在更新嵌套数组时遇到困难,尤其是无法正确更新roles数组中的sources子数组,需要指导正确的写法。

示例文档

{
  "_id": "67448af8-a68b-4d08-8948-2cddca57d708",
  "identity": {
    "_id": "7.26Demo@test.com",
    "type": "Email"
  },
  "type": "User",
  "links": [
    {
      "linkType": "Org",
      "linkPath": "0923689a-e009-4d67-8db5-5ba40f840bf3/facd3c31-dbfd-4097-9a27-0d862bb0c8e9",
      "status": "Activated",
      "createdOn": {
        "$date": "2022-07-26T14:49:38.780Z"
      },
      "createdBy": ""
    }
  ],
  "memberOfGroups": [
    {
      "_id": "ba93384d-d18a-4b36-9a24-7d3ebb1619d7",
      "name": "test group"
    }
  ],
  "roles": [
    {
      "_id": "ba93384d-d18a-4b36-9a24-7d3ebb1619d7",
      "name": "test group",
      "sources": [
        {
          "type": "group",
          "linkType": "app",
          "groupId": "ba93384d-d18a-4b36-9a24-7d3ebb1619d7"
        }
      ]
    }
  ]
}

原错误更新管道

我使用了以下update pipeline,但无法更新roles数组中的sources子数组:

db.principals.update({
  _id: "67448af8-a68b-4d08-8948-2cddca57d708"
},
[
  {
    $set: {
      "memberOfGroups": {$ifNull: ["$memberOfGroups", []]}
    }
  },
  {
    $set: {
      "roles": {$ifNull: ["$roles", []]}
    }
  },
  {
    $set: {
      "memberOfGroups": {
        $cond: [
          {
            $ne: [
              "$memberOfGroups._id",
              "ba93384d-d18a-4b36-9a24-7d3ebb1619d7"
            ]
          },
          {
            $concatArrays: [
              "$memberOfGroups.items",
              [
                {
                  _id: "ba93384d-d18a-4b36-9a24-7d3ebb1619d7",
                  name: "test group"
                }
              ]
            ]
          },
          {$concatArrays: ["$memberOfGroups.items", []]}
        ]
      }
    }
  },
  {
    $set: {
      "roles": {
        $cond: [
          {
            $ne: [
              "$roles._id",
              "ba93384d-d18a-4b36-9a24-7d3ebb1619d7"
            ]
          },
          {
            $concatArrays: [
              "$roles.items",
              [
                {
                  _id: "ba93384d-d18a-4b36-9a24-7d3ebb1619d7",
                  name: "test group",
                  sources: [
                    {
                      type: "group",
                      linkType: "app",
                      groupId: "ba93384d-d18a-4b36-9a24-7d3ebb1619d7"
                    }
                  ]
                }
              ]
            ]
          },
          {}
        ]
      }
    }
  },
  {
    $set: {
      roles: {
        $reduce: {
          input: {$ifNull: ["$roles", []]},
          initialValue: {
            role: {
              _id: "0923689a-e009-4d67-8db5-5ba40f840bf3",
              name: "testRole",
              sources: [
                {
                  type: "group",
                  linkType: "org"
                }
              ]
            },
            sources: [
              {
                type: "group",
                linkType: "org",
                groupid: "0923689a-e009-4d67-8db5-5ba40f840bf3"
              }
            ]
          },
          in: {
            $cond: [
              {$eq: [
                  "$$this.roleid",
                  "0923689a-e009-4d67-8db5-5ba40f840bf3"
                ]
              },
              {$cond: [
                  {$ne: [
                      "$$this.sources.groupId",
                      "0923689a-e009-4d67-8db5-5ba40f840bf3"
                    ]
                  },
                  {$concatArrays: ["$$this.sources", "$$value.sources"]},
                  {$concatArrays: ["$$this.sources", []]}
                ]
              },
              {}
            ]
          }
        }
      }
    }
  }
])

需求说明

  • 若memberOfGroups数组中不存在指定groupId的元素,则添加对应的memberOfGroup对象;
  • 若roles数组中不存在指定roleId的元素,则添加对应的Role对象;
  • 若roles数组存在匹配roleId的元素,但sources子数组无指定groupId元素,则添加对应的source对象。

正确的更新管道

针对上述需求,以下是可以实现功能的update pipeline:

db.principals.update({
  _id: "67448af8-a68b-4d08-8948-2cddca57d708"
},
[
  // 初始化空数组避免null问题
  {
    $set: {
      memberOfGroups: {$ifNull: ["$memberOfGroups", []]},
      roles: {$ifNull: ["$roles", []]}
    }
  },
  // 处理memberOfGroups:不存在则添加
  {
    $set: {
      memberOfGroups: {
        $cond: [
          {
            $in: [
              "ba93384d-d18a-4b36-9a24-7d3ebb1619d7",
              "$memberOfGroups._id"
            ]
          },
          "$memberOfGroups",
          {
            $concatArrays: [
              "$memberOfGroups",
              [{_id: "ba93384d-d18a-4b36-9a24-7d3ebb1619d7", name: "test group"}]
            ]
          }
        ]
      }
    }
  },
  // 处理roles数组:先判断是否存在目标role,不存在则添加;存在则更新其sources
  {
    $set: {
      roles: {
        $let: {
          vars: {
            targetRoleId: "0923689a-e009-4d67-8db5-5ba40f840bf3",
            newRole: {
              _id: "0923689a-e009-4d67-8db5-5ba40f840bf3",
              name: "testRole",
              sources: [{type: "group", linkType: "org", groupId: "0923689a-e009-4d67-8db5-5ba40f840bf3"}]
            },
            newSource: {type: "group", linkType: "org", groupId: "0923689a-e009-4d67-8db5-5ba40f840bf3"}
          },
          in: {
            $cond: [
              // 判断是否存在目标role
              {
                $in: ["$$targetRoleId", "$roles._id"]
              },
              // 存在则遍历roles,更新匹配的role的sources
              {
                $map: {
                  input: "$roles",
                  as: "role",
                  in: {
                    $cond: [
                      {$eq: ["$$role._id", "$$targetRoleId"]},
                      {
                        $mergeObjects: [
                          "$$role",
                          {
                            sources: {
                              $cond: [
                                // 判断sources中是否存在目标groupId
                                {
                                  $in: ["$$newSource.groupId", "$$role.sources.groupId"]
                                },
                                "$$role.sources",
                                {$concatArrays: ["$$role.sources", ["$$newSource"]]}
                              ]
                            }
                          }
                        ]
                      },
                      "$$role"
                    ]
                  }
                }
              },
              // 不存在则添加新role
              {$concatArrays: ["$roles", ["$$newRole"]]}
            ]
          }
        }
      }
    }
  }
])

代码解释

  1. 初始化数组:用$ifNull确保memberOfGroups和roles始终是数组,避免后续操作报错;
  2. 处理memberOfGroups:通过$in判断目标groupId是否存在,不存在则用$concatArrays添加新对象;
  3. 处理roles及嵌套sources:
    • 使用$let定义变量,让代码更清晰;
    • 先通过$in判断目标roleId是否存在于roles数组中;
    • 若存在,用$map遍历roles,对匹配的role使用$mergeObjects更新其sources:再次通过$in判断目标groupId是否在sources中,不存在则用$concatArrays添加新source;
    • 若不存在,直接用$concatArrays添加新的role对象。

内容的提问来源于stack exchange,提问作者user2252915

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 04:24:12