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 版本是否存在任何限制使得此类实施不可能的问题。
感谢您的帮助。
对于您的场景,通过使用聚合管道的更新查询来实现它。
$set
- 获取 logs
的最后一个元素作为 lastLog
.
$set
2.1 $concatArrays
- 将数组与 logs
的所有元素(最后一个文档除外)和 2.2.
的结果合并
2.2 $mergeObjects
- 合并对象 lastLog
和 2.3 的结果旨在覆盖 app_logs
字段。
2.3 $mergeArrays
- 合并数组 lastLog.app_logs
和新文档(作为数组)。
$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"
}
])
我想知道是否可以在 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 版本是否存在任何限制使得此类实施不可能的问题。 感谢您的帮助。
对于您的场景,通过使用聚合管道的更新查询来实现它。
$set
- 获取logs
的最后一个元素作为lastLog
.$set
2.1
的结果合并$concatArrays
- 将数组与logs
的所有元素(最后一个文档除外)和 2.2.2.2
$mergeObjects
- 合并对象lastLog
和 2.3 的结果旨在覆盖app_logs
字段。2.3
$mergeArrays
- 合并数组lastLog.app_logs
和新文档(作为数组)。$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"
}
])