0

I need to update a property which is an array, existing within another array in my MongoDB collection. Now, this works:

  {
    "_id": request.parameters.id
  },
  {
    $set: { "services.2.history": historyArray }
  },
  {
    new: true
  }

... but I don't want to trust that the element I'm targeting will always be the in position 2. I do know the value of a property in the target element, however:

{
  _id: <value>,
  category: 'evaluation', // I know the correct array element has this value
  startDate: <date>
}

So, that said, is there a way I can pass that value in here in order to target the correct array element within services using the $[] operator and arrayFilters?

I tried this but it's not working:

  {
    _id: request.parameters.id
  },
  {
    $set: { "services.$[element].history": historyArray }
  },
  { arrayFilters: [{ element: { "$services.category": targetService.category } }] },
  {
    new: true
  }

No errors. Just doesn't seem to update the document as expected. Am I missing something here? What should the syntax look like here? I want it to update the array element for services where the "category" property has the value of "evaluation".

Muirik
  • 6,049
  • 7
  • 58
  • 116
  • Your element does not have a `$services.category` key/property. How about using `arrayFilters: [{ "element.category": targetService.category }]` in your last query? – Mihai Potra Jan 11 '19 at 18:47
  • Good idea. Still didn't work though. Not sure why. – Muirik Jan 11 '19 at 18:52
  • BTW, your last object parameter `{new: true}` is not used, in `.update()` calls. – Mihai Potra Jan 11 '19 at 18:56
  • I am trying this with a "findOneAndUpdate()". Do I need to use "update()"? – Muirik Jan 11 '19 at 18:57
  • Have you made sure there are both a document with `_id` set to the value of `request.parameters.id` (ensure `request.parameters.id` is not undefined), and the document has an object with `category` property matching the value of `targetService.category` value (also to be checked) inside the `services` array? – Mihai Potra Jan 11 '19 at 19:01
  • `findOneAndUpdate()` is good, but still no 4th parameter. – Mihai Potra Jan 11 '19 at 19:03
  • You may already be using it, but it's worth mentioning that `$[]` requires MongoDB 3.6+ – Mihai Potra Jan 11 '19 at 19:09
  • Yes, I'm on MongoDB 4. – Muirik Jan 11 '19 at 19:13
  • Also mongoose v5+ or mongodb v3+ drivers, I presume? – Mihai Potra Jan 11 '19 at 19:40
  • Yes, that's my problem. We ran into a host of issues when trying to update Mongoose. Do you know of a workaround in that case, even if it's more verbose? – Muirik Jan 11 '19 at 19:44
  • There appears to be a workaround for older drivers, described here: https://stackoverflow.com/a/47233482 – Mihai Potra Jan 11 '19 at 19:51
  • Interesting, thanks. Just thinking through what this would look like in my case. – Muirik Jan 11 '19 at 19:58
  • Most likely something along the lines: `let result = await conn.db.command({ "update": YourSchema.collection.name, "updates": [ { "q": {_id: request.parameters.id}, "u": { "$set": { "services.$[element].history": historyArray } }, "arrayFilters": [{ "element.category": targetService.category }] } ] });` – Mihai Potra Jan 11 '19 at 20:08
  • Does Mongoose support this? – Muirik Jan 11 '19 at 20:12

0 Answers0