代码之家  ›  专栏  ›  技术社区  ›  Mark Bramnik

Mongo DB更新对象的部分

  •  0
  • Mark Bramnik  · 技术社区  · 4 年前

    我有一个集合,它根据一些执行流存储文档。 每个过程包括“过程”,每个过程包括步骤。 因此,我最终得到了一个“流”集合,其中的文档如下所示:

    {
       "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"}})
    

    然而,我不知道如何更新步骤状态,给定flowId、进程Id和步骤Id,看起来它不允许在路径中使用多个“$”符号:

    所以,这不起作用:

    db.getCollection('flows').updateOne({"name" : "flow1", "processes" : {$elemMatch : {"processId" : "firstProcessId"}}, "processes.steps.stepId" : {$elemMatch : {"stepId" : "foo"}}}, {$set: {"processes.$.steps.$.status" : "RUNNING"}})
    

    实现这种更新的最佳方式是什么?

    2 回复  |  直到 4 年前
        1
  •  3
  •   Yong Shun    4 年前

    要更新多层嵌套数组中的文档,需要 $[<identifier>] 过滤位置运算符和 arrayFilters .

    还有 processes processes.steps.stepId 在中执行筛选时,可以删除匹配运算符中的筛选 阵列过滤器 .

    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 $[]

        2
  •  3
  •   Tom Slabbaert    4 年前

    正如您提到的,它不能直接用于多个阵列 docs :

    positional$运算符不能用于遍历多个数组的查询,例如遍历嵌套在其他数组中的数组的查询,因为$占位符的替换项是单个值

    我建议你使用 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