Mongo 数据库更新部分对象
Mongo DB updating parts of object
我有一个集合,可以按某些执行流程存储文档。
每个过程都包含“过程”,每个过程都包含步骤。
所以我最终得到一个 'flows' 集合,其中包含如下所示的文档:
{
"name" : "flow1",
"description" : "flow 1 description",
"processes" : [
{
"processId" : "firstProcessId",
"name" : "firstProcessName",
"startedAt" : null,
"finishedAt" : null,
"status" : "PENDING",
"steps" : [
{
"stepId" : "foo",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
},
{
"stepId" : "bar",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
}
...
]
},
{
"processId" : "secondProcessId",
"name" : "secondProcessName",
"startedAt" : null,
"finishedAt" : null,
"status" : "PENDING",
"steps" : [
{
"stepId" : "foo",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
},
{
"stepId" : "xyz",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
}
...
]
}
}
这里有几点说明:
每个流程包含许多流程
每个进程至少包含一个步骤,有可能在不同的进程中出现相同id的步骤(id是程序员指定的),
它可能类似于“从数据库中给我带来一些东西的步骤”,所以这是我系统中的一种可重用组件。
现在,当应用程序运行时,我想调用 DAO 的方法,例如
“startProcess”、“startStep”
所以我想知道给定 processId 和步骤的开始步骤的正确查询是什么。
给定流程 ID 和流程 ID,我可以成功地将流程描述更新为“运行”:
db.getCollection('flows').updateOne({"name" : "flow1", "processes" : {$elemMatch : {"processId" : "firstProcessId"}}}, {$set: {"processes.$.status" : "RUNNING"}})
但是我不知道如何根据流程 ID、流程 ID 和步骤 ID 更新步骤状态,它看起来不允许路径中有多个“$”符号:
所以,这行不通:
db.getCollection('flows').updateOne({"name" : "flow1", "processes" : {$elemMatch : {"processId" : "firstProcessId"}}, "processes.steps.stepId" : {$elemMatch : {"stepId" : "foo"}}}, {$set: {"processes.$.steps.$.status" : "RUNNING"}})
实施此类更新的最佳方式是什么?
要更新 multi-level 嵌套数组中的文档,您需要 $[<identifier>]
过滤位置运算符和 arrayFilters
.
并且可以删除匹配运算符中的 processes
和 processes.steps.stepId
过滤器,因为过滤器是在 arrayFilters
中执行的。
db.collection.update({
"name": "flow1"
},
{
$set: {
"processes.$[process].steps.$[step].status": "RUNNING"
}
},
{
arrayFilters: [
{
"process.processId": "firstProcessId"
},
{
"step.stepId": "foo"
}
]
})
参考
正如您所提到的,它不适用于多个数组,直接来自 docs:
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
我建议您改用 arrayFilters,它的行为更加清晰,尤其是在使用嵌套结构时:
db.collection.updateMany(
{
"name": "flow1",
"processes.processId": "firstProcessId",
"processes.steps.stepId": "foo"
},
{
$set: {
"processes.$[process].steps.$[step].status": "RUNNING"
}
},
{
arrayFilters: [
{
"process.processId": "firstProcessId"
},
{
"step.stepId": "foo"
}
]
})
我有一个集合,可以按某些执行流程存储文档。 每个过程都包含“过程”,每个过程都包含步骤。 所以我最终得到一个 'flows' 集合,其中包含如下所示的文档:
{
"name" : "flow1",
"description" : "flow 1 description",
"processes" : [
{
"processId" : "firstProcessId",
"name" : "firstProcessName",
"startedAt" : null,
"finishedAt" : null,
"status" : "PENDING",
"steps" : [
{
"stepId" : "foo",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
},
{
"stepId" : "bar",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
}
...
]
},
{
"processId" : "secondProcessId",
"name" : "secondProcessName",
"startedAt" : null,
"finishedAt" : null,
"status" : "PENDING",
"steps" : [
{
"stepId" : "foo",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
},
{
"stepId" : "xyz",
"status" : "PENDING",
"startedAt" : null,
"finishedAt" : null
}
...
]
}
}
这里有几点说明: 每个流程包含许多流程 每个进程至少包含一个步骤,有可能在不同的进程中出现相同id的步骤(id是程序员指定的),
它可能类似于“从数据库中给我带来一些东西的步骤”,所以这是我系统中的一种可重用组件。
现在,当应用程序运行时,我想调用 DAO 的方法,例如 “startProcess”、“startStep”
所以我想知道给定 processId 和步骤的开始步骤的正确查询是什么。
给定流程 ID 和流程 ID,我可以成功地将流程描述更新为“运行”:
db.getCollection('flows').updateOne({"name" : "flow1", "processes" : {$elemMatch : {"processId" : "firstProcessId"}}}, {$set: {"processes.$.status" : "RUNNING"}})
但是我不知道如何根据流程 ID、流程 ID 和步骤 ID 更新步骤状态,它看起来不允许路径中有多个“$”符号:
所以,这行不通:
db.getCollection('flows').updateOne({"name" : "flow1", "processes" : {$elemMatch : {"processId" : "firstProcessId"}}, "processes.steps.stepId" : {$elemMatch : {"stepId" : "foo"}}}, {$set: {"processes.$.steps.$.status" : "RUNNING"}})
实施此类更新的最佳方式是什么?
要更新 multi-level 嵌套数组中的文档,您需要 $[<identifier>]
过滤位置运算符和 arrayFilters
.
并且可以删除匹配运算符中的 processes
和 processes.steps.stepId
过滤器,因为过滤器是在 arrayFilters
中执行的。
db.collection.update({
"name": "flow1"
},
{
$set: {
"processes.$[process].steps.$[step].status": "RUNNING"
}
},
{
arrayFilters: [
{
"process.processId": "firstProcessId"
},
{
"step.stepId": "foo"
}
]
})
参考
正如您所提到的,它不适用于多个数组,直接来自 docs:
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
我建议您改用 arrayFilters,它的行为更加清晰,尤其是在使用嵌套结构时:
db.collection.updateMany(
{
"name": "flow1",
"processes.processId": "firstProcessId",
"processes.steps.stepId": "foo"
},
{
$set: {
"processes.$[process].steps.$[step].status": "RUNNING"
}
},
{
arrayFilters: [
{
"process.processId": "firstProcessId"
},
{
"step.stepId": "foo"
}
]
})