Skip to content
Advertisement

Mongo DB updating parts of object

I have the collection that stores documents per some execution Flow. Every Process includes “processes” and each process includes steps. So I end up with a ‘flows’ collection that has documents that look like this:

{
   "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 
        }
        ...
      ​]
    }
}

A couple of notes here: Each flow contains many processes Each each process contains at least one step, its possible that in different processes the steps with the same id might appear (id is something that the programmer specifies),

it can be something like “step of bring me something from the DB”, so this is a kind of reusable component in my system.

Now, when the application runs I would like to call DAO’s method like “startProcess”, “startStep”

So I would like to know what is the correct query for starting step given processId and steps.

I can successfully update the process description to “running” given the flow Id and the process Id:

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

However I don’t know how to update the step status given the flowId, process Id and step Id, it looks like it doesn’t allow multiple “$” signs in the path:

So, this doesn’t work:

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

What is the best way to implement such an update?

Advertisement

Answer

To update the document in multi-level nested array, you need $[<identifier>] filtered positional operator and arrayFilters.

And the processes and processes.steps.stepId filter in the match operator can be removed as the filter is performed in arrayFilters.

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

Sample Mongo Playground


Reference

Update Nested Arrays in Conjunction with $[]

Advertisement