更新数组中的对象或使用唯一字段插入数组

Update an object in array or insert into the array using a unique field

我有一个文档,其中包含一个包含对象元素的数组 属性。

例如

{
    "_id": "61c01098bc29520008efc00f",
    "name": "codedump",
    "employments": [
         {
              "type": "PERMANENT",
              "salary": 1000000000
         },
         {
              "type": "TEMP",
              "salary": 1000000000
         },
         {
              "type": "PART_TIME",
              "salary": 1000000000
         },
    ]
}

并且在使用 type 更新就业工资时,如果该类型已经在就业中,那么我只需要更新 salary。否则我需要将新项目推送到数组。我正在尝试找到一种方法来在单个查询中完成这项工作。

  1. 如果类型已经存在于数组中(用于更新):
/// Update data:
             {
                  "type": "PERMANENT",
                  "salary": 10
             }
// For this case I want the example document to become:
{
    "_id": "61c01098bc29520008efc00f",
    "name": "codedump",
    "employments": [
         {
              "type": "PERMANENT",
              "salary": 10 // From 1000000000 to 10         
         },
         {
              "type": "TEMP",
              "salary": 1000000000
         },
         {
              "type": "PART_TIME",
              "salary": 1000000000
         },
    ]
}
  1. 如果类型不存在:
/// Update data:
             {
                  "type": "INVESTMENT",
                  "salary": 10000
             }
// For this case I want the example document to become:
{
    "_id": "61c01098bc29520008efc00f",
    "name": "codedump",
    "employments": [
         {
              "type": "PERMANENT",
              "salary": 1000000000      
         },
         {
              "type": "TEMP",
              "salary": 1000000000
         },
         {
              "type": "PART_TIME",
              "salary": 1000000000
         },
         {
              "type": "INVESTMENT",
              "salary": 10000
         }
    ]
}

不知道你要的是不是一次操作就可以...

话虽如此,我会怎么做,使用 $ 位置运算符来更新我想要的数组元素。 Doc & playground.

db.collection.update({
  "employments.type": "PERMANENT",
  
},
{
  "$set": {
    "employments.$.salary": 10
  }
},
{
  "multi": false,
  "upsert": false
})

此操作仅在元素存在于数组中时有效。如果不是,则操作将失败。然后您可以在代码中捕获异常并使用 $push 执行插入。 Playground

db.collection.update({},
{
  "$push": {
    "employments": [
      {
        "type": "INVESTMENT",
        "salary": 10000
      }
    ]
  }
},
{
  "multi": false,
  "upsert": false
})

技术上可以在 1 次调用中实现,从 Mongo v4.2 开始你可以使用 pipelined updates,这实际上允许你在更新主体中使用聚合运算符,因此你可以实现很多任何东西。

我会说,但它绝对不是很有效,这实际上取决于您想要 maximize/minimize(网络/数据库负载等)系统的哪一部分。

您可以这样做:

const input =  {
  "type": "INVESTMENT",
  "salary": 10000
}

db.collection.update({},
[
  {
    $set: {
      employments: {
        $cond: [
          {
            $in: [
              input.type,
              "$employments.type"
            ]
          },
          {
            $map: {
              input: "$employments",
              in: {
                $cond: [
                  {
                    $eq: [
                      "$$this.type",
                      input.type,
                    ]
                  },
                  {
                    type: "$$this.type",
                    salary: input.salary
                  },
                  "$$this"
                ]
              }
            }
          },
          {
            $concatArrays: [
              "$employments",
              [
                input
              ]
            ]
          }
        ]
      }
    }
  }
])

Mongo Playground