MongoDB 使用 findOneAndUpdate 推送到嵌套数组

MongoDB push to nested array with findOneAndUpdate

我想知道是否可以在 findOneAndUdate() 方法的一次调用中实现以下问题。 让我们考虑这个集合条目:

[
  {
    "key": 1,
    "logs": [
      {
        "app_logs": [
          {
            "stdout": "app_stdout_1",
            "stderr": "app_stderr_1"
          }
        ],
        "syslog": "syslog_val1"
      },
      {
        "app_logs": [
          {
            "stdout": "app_stdout_2",
            "stderr": "app_stderr_2"
          }
        ],
        "syslog": "syslog_val2"
      }
    ]
  },
  
]

我需要将其他元素推入“app_logs”数组,但只能在“logs”数组的最后一个条目内。目前为了绕过这个问题,我按原样获取文档,在应用程序中执行这样的推送,然后使用 findOneAndReplace() 方法。虽然这有效,但我希望通过单个 MongoDB 调用来实现它。我尝试了各种方法,如管道聚合、更新数组过滤器等,但无法使它们中的任何一种起作用。也尝试在网上寻找解决方案,阅读文档但仍然找不到任何成功解决的类似问题。

人们最常遇到的类似问题是在条件下更新嵌套数组中的特定元素,这可以通过使用位置运算符来解决,例如:

findOneAndUpdate({
  "key": 1,
  "logs.syslog": "syslog_val1"
},
{
  "$push": {
    "logs.$.app_logs": {
      "stdout": "app_stdout_new",
      "stderr": "app_stderr_new"
    }
  }
})

在我的例子中,我不想对“logs”数组的特定元素执行这样的推送,而只是对最后一个元素执行。由于我已经在这个问题上花费了很多时间,这让我想到了是否有可能实施或者当前 MongoDB 版本是否存在任何限制使得此类实施不可能的问题。 感谢您的帮助。

对于您的场景,通过使用聚合管道的更新查询来实现它。

  1. $set - 获取 logs 的最后一个元素作为 lastLog.

  2. $set

    2.1 $concatArrays - 将数组与 logs 的所有元素(最后一个文档除外)和 2.2.

    的结果合并

    2.2 $mergeObjects - 合并对象 lastLog 和 2.3 的结果旨在覆盖 app_logs 字段。

    2.3 $mergeArrays - 合并数组 lastLog.app_logs 和新文档(作为数组)。

  3. $unset - 删除 lastLog 字段。

db.collection.update({
  "key": 1,
  "logs.syslog": "syslog_val1"
},
[
  {
    $set: {
      "lastLog": {
        $arrayElemAt: [
          "$logs",
          -1
        ]
      }
    }
  },
  {
    $set: {
      "logs": {
        $concatArrays: [
          {
            $slice: [
              "$logs",
              {
                $add: [
                  {
                    $size: "$logs"
                  },
                  -1
                ]
              }
            ]
          },
          [
            {
              $mergeObjects: [
                "$lastLog",
                {
                  "app_logs": {
                    $concatArrays: [
                      "$lastLog.app_logs",
                      [
                        {
                          "stdout": "app_stdout_new",
                          "stderr": "app_stderr_new"
                        }
                      ]
                    ]
                  }
                }
              ]
            }
          ]
        ]
      }
    }
  },
  {
    $unset: "lastLogs"
  }
])

Sample Mongo Playground