0

I'm trying to do something with Mongo but I'm stuck. I'm certain the answer is super easy but I can't find it out. Thank you very much for your help.

I have a document (see below) I want to update.

{
  _id: ObjectId("57d52d9c56f0dc1c93254265"),
  processus: [
    {
      action: "action 1",
      date: ISODate("2016-08-23T22:00:00Z")
    },
    {
      action: "action 2",
      date: ISODate("2016-12-11T23:00:00Z")
    }
  ]
}

More precisely, I want to "change the date" of action 1. For example, I want to make my document like this:

{
  _id: ObjectId("57d52d9c56f0dc1c93254265"),
  processus: [
    {
      action: "action 1",
      date: "another date"
    },
    {
      action: "action 2",
      date: ISODate("2016-12-11T23:00:00Z")
    }
  ]
}

Below my update statement (which doesn't work / same thing with $push)

db.collection('...').update(
     { _id : ObjectId(...) },
     { $addToSet: {
          processus: {
            $each: [ { "action" : "action 1", "date" : "another date" } ],
          }
     }}
)

Indeed, the resulting document is:

{
  _id: ObjectId("57d52d9c56f0dc1c93254265"),
  processus: [
    {
      action: "action 1",
      date: "another date"
    },
    {
      action: "action 1",
      date: ISODate("2016-08-23T22:00:00Z")
    },
    {
      action: "action 2",
      date: ISODate("2016-12-11T23:00:00Z")
    }
  ]
}

Any idea? Thanks again.

2 Answers 2

1

For doing this you need to use $set with the positional operator $

db.collection('...').update(
 { _id : ObjectId("..."),
  "processus.action": "action 1" 
 },
 { $set: { 
    "processus.$.date": "another date"
 }          
})

The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.The positional operator acts as a placeholder for the first entry in the array that match the filter(query document) sent to the update command.

Sign up to request clarification or add additional context in comments.

2 Comments

It works - almost - perfectly. Indeed, it works only if processus.action : action 1 exists. Both the id and action 1 are in the "filter part"... So how to make processus.action : action 1 be updated with another date' if it already exists, or be "insert" if it doesn't. A little bit like upsert : true` ? Thanks again.
The positional operator cannot be combined with an upsert since it requires a matching array element.
0

You can use $set for an array of subdocuments with a numerical array key:

db.collection.update({ _id: ... }, { $set: { processus.0.date: another_date }})

2 Comments

Thanks. The problem is that I sort all these actions by date. So action[0] changes over time. So your proposal does not apply... Do you have any other idea? Thank you very much
In this case you have to rewrire a whole array, or load it in your code, calculate the position of the necessary element and perform an update. I think there are no other options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.