9

How can I update a record in a document with multiple levels of array nesting?

My document structure is the following:

{
  "_id": "5bfa09f0a0441f38d45dcc9c",
  "nombre": "PROYECTO MAIN",
  "area": "Sistemas",
  "fecha": "27/01/2018",
  "reuniones": [
    {
      "_id": "5bfa09f0a0441f38d45dcc99",
      "objetivo": "Objetivo MODIFICADO",
      "fecha": "25/10/2018",
      "participantes": [
        {
          "nomina": 1,
          "nombre": "MODIFICADO",
          "rol": "rol",
          "area": "area",
          "firma": "url/imagen.jpg"
        },
        {
          "nomina": 2,
          "nombre": "nombre 2",
          "rol": "rol",
          "area": "area",
          "firma": "url/imagen.jpg"
        }
      ]
    }
  ],
  "_class": "proyecto"
}

Using the following query, returns me the document mentioned above.

 db.proyectos.find({
    _id:ObjectId("5bfa09f0a0441f38d45dcc9c"),
    "reuniones._id":ObjectId("5bfa09f0a0441f38d45dcc99"), 
    "reuniones.participantes.nomina":2 
 })

I want to update the firma field of participant with nomina 2.

1 Answer 1

20

Since Mongo 3.6, you can update multi-nested arrays by combining the following operators:

  • $set (to update a specific field)
  • $[] (to match any item in an array)
  • $[<identifier>] (to match specific items in an array)

Example

Here's how you can update a specific proyectos document that has a reuniones array that has a participantes array that has an object with the field nomina equal to 2:

// update a specific proyectos document
// that has a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2
db.proyectos.update({
  _id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
  $set: {
    "reuniones.$[].participantes.$[j].firma": <your update>
  },
}, { 
  arrayFilters: [
    {
      "j.nomina": 2
    }
  ]
})

If you wanted to limit your query to a specific reunion, you can do:

db.proyectos.update({
  _id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
  $set: {
    "reuniones.$[i].participantes.$[j].firma": <your update>
  },
}, { 
  arrayFilters: [
    {
      "i._id": ObjectId("5bfa09f0a0441f38d45dcc99")
    },
    {
      "j.nomina": 2
    }
  ]
})

To update all proyectos satisfying the above condition, just omit the _id query:

// update all proyectos
// that have a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2    
db.proyectos.update({}, {
  $set: {
    "reuniones.$[].participantes.$[j].firma": <your update>
  },
}, { 
  arrayFilters: [
    {
       "j.nomina": 2
    }
  ]
})
Sign up to request clarification or add additional context in comments.

5 Comments

But how can I limit the update to the reunion that has _id ": ObjectId (" 5bfa09f0a0441f38d45dcc99 "). This is because the proyecto document has many reuniones, each with a different id. The query that you suggest modifies the firma field of all participantes with nomina 2 that are in the reuniones array, right?
@Gibrán I added an example for a specific reuniones document
Sorry @nem045, Is there no other alternative to achieve the same result but without arrayFilters? My problem is that I want to replicate the query in spring boot but the current driver does'nt allow me to run an update with arrayFilters. I appreciate any suggestion. Even generate a question but it seems that went unnoticed.
Not an easy direct query no, you'd have to do some manual in-memory iteration (via a cursor) once the data is obtained afaik
If you are using underscore in query, mongo database does not support underscore. stackoverflow.com/questions/58219745/…

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.