Search code examples
mongodbmongoosemongoose-schema

Mongoose, Update an object inside an array which is inside another array


Is there a way to update and object inside and array which is also inside another array like in this example?

this is how the collection would be like:

{
  "_id": "5fd3966d2769d212dc0104a4",
  "Races": [
    {
      "_id": "5fd3966d2769dc12dc0105f4",
      "gpName": "Sakhir Grand Prix",
      "RaceResult": [
        {
          "_id": "5fd3966d2769dc12dc0105e0",
          "position": "First",
          "driverName": "Hamilton"
        },
        {
          "_id": "5fd3966d2769dc12dc0105e1",
          "position": "Second",
          "driverName": "Vettel"
        }
      ]
    },
    {
      "_id": "5fd3966d2769dc12dc0105df",
      "gpName": "Abu Dhabi Grand Prix",
      "RaceResult": [
        {
          "_id": "5fd39452d2769dc12dc0105df",
          "position": "First",
          "driverName": "Bottas"
        },
        {
          "_id": "5fd3966d2769dc12dc0105e2",
          "position": "Second",
          "driverName": "Hamilton"
        }
      ]
    }
  ]
}

So If I want to change for example, "United States Grand Prix" instead of "Sakhir Grand Prix", I would go with:

StandingsModel.updateOne({ "Races._id": "5fd3966d2769dc12dc0105f4"}, {
        "$set": {
            "Races.$.gpName": 'United States Grand Prix'}
})

But how can I change the "driverName" or "position" value inside RaceResults?.

I've tried with setting:

(For clarification, in this example I wanna change the second driver name inside Abu Dhabi GP)

StandingsModel.updateOne({ "Races.RaceResults._id": "5fd3966d2769dc12dc0105e2"}, {
        "$set": {
            "Races.$.RaceResults.$.driverName": 'Vettel'}
})

But of course this don't work as expected and mongoose send back an error code 2.

Any idea?

Thanks.


Solution

  • You can use $[<identifier>]. Also there is an specific section called Update Nested Arrays in Conjunction with $[].

    You can use this way to filter the array looking for your Race id first and after your RaceResult id.

    You can use this query:

    db.collection.update(
    { "_id": "5fd3966d2769d212dc0104a4" },
    { "$set": { "Races.$[race].RaceResult.$[result].driverName": "Vettel" } },
    { "arrayFilters": [ 
       { "race._id": "5fd3966d2769dc12dc0105df" },
       { "result.position": "Second" } ] 
    })
    

    The $set stage will modify the object into Race array that match the filter race. And inside race array, will filter by result filter.

    That is: The query will get one race by its id using filter race._id and inside the race only the object where position is Second will be updated.

    So the query will update the object you want. You can check an example here