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.

并且可以删除匹配运算符中的 processesprocesses.steps.stepId 过滤器,因为过滤器是在 arrayFilters 中执行的。

db.collection.update({
  "name": "flow1"
},
{
  $set: {
    "processes.$[process].steps.$[step].status": "RUNNING"
  }
},
{
  arrayFilters: [
    {
      "process.processId": "firstProcessId"
    },
    {
      "step.stepId": "foo"
    }
  ]
})

Sample Mongo Playground


参考

Update Nested Arrays in Conjunction with $[]

正如您所提到的,它不适用于多个数组,直接来自 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"
    }
  ]
})

Mongo Playground