MongoDB: ¿Cómo actualizo un único subelemento en una matriz, al que hace referencia el índice dentro de la matriz?

84

Estoy intentando actualizar un solo subelemento contenido dentro de una matriz en un documento mongodb. Quiero hacer referencia al campo usando su índice de matriz (los elementos dentro de la matriz no tienen ningún campo que pueda garantizar que serán identificadores únicos). Parece que esto debería ser fácil de hacer, pero no puedo entender la sintaxis.

Esto es lo que quiero hacer en pseudo-json.

Antes de:

{
  _id : ...,
  other_stuff ... ,
  my_array : [
    { ... old content A ... },
    { ... old content B ... },
    { ... old content C ... }
  ]
}

Después:

{
  _id : ...,
  other_stuff ... ,
  my_array : [
    { ... old content A ... },
    { ... NEW content B ... },
    { ... old content C ... }
  ]
}

Parece que la consulta debería ser algo como esto:

//pseudocode
db.my_collection.update(
  {_id: ObjectId(document_id), my_array.1 : 1 },
  {my_array.$.content: NEW content B }
)

Pero esto no funciona. He pasado demasiado tiempo buscando en los documentos de mongodb y probando diferentes variaciones de esta sintaxis (por ejemplo $slice, usando , etc.). No puedo encontrar una explicación clara de cómo realizar este tipo de actualización en MongoDB.

Abe
fuente

Respuestas:

76

Como era de esperar, la consulta es fácil una vez que sepa cómo. Aquí está la sintaxis, en python:

db["my_collection"].update(
    { "_id": ObjectId(document_id) },
    { "$set": { 'documents.'+str(doc_index)+'.content' : new_content_B}}
)
Abe
fuente
13
donde esta documentado?
ROROROOROROR
Esto termina creando un objeto con el mismo nombre en lugar de actualizar la matriz
Kisinga
Definitivamente es una respuesta obsoleta.
Mark Odey
49

La actualización de un elemento de matriz al que hace referencia un índice (por ejemplo, 1) en Mongo Shell también se puede realizar indicando directamente el valor del índice:

db.my_collection.update(
    {_id : "document_id"},
    {$set : {"my_array.1.content" : "New content B"}}
)
tomaskazemekas
fuente
¿Cómo lo hacemos si no conocemos el índice?
Muhammad Shahzad
46

En estilo mongo, usando el operador posicional '$'. Consulte este enlace para obtener más detalles.

db.my_collection.update(
  {_id: ObjectId(document_id), my_array.1 : 1 },
  { $set: { "my_array.$.content" : "NEW content B" } }
)
Doel
fuente
¡Esa es la mejor respuesta!
Bogdan Kobylynskyi
8
db.my_collection.update(
  {_id: ObjectId(document_id), my_array : { ... old content A ... } },
  { $set: { "my_array.$.content" : "NEW content B" } }
)
znbwo
fuente
5

Cuando se requiere actualizar un elemento de matriz sin saber su índice real pero con un identificador único del elemento:

// Modify a comment in a bucket
db.POST_COMMENT.update(
    {
        "_id": ObjectId("5ec424a1ed1af85a50855964"),
        "bucket.commentId": "5eaf258bb80a1f03cd97a3ad_lepf4f"
    },
    {
        $set: {
            "bucket.$.text": "Comment text changed",
            "bucket.$.createdDate": ISODate("2015-12-11T14:12:00.000+0000")
        }
    }
)

Aquí "bucket.commentId"está el identificador único de un elemento de matriz.

iamcrypticcoder
fuente
En el shell de Mongo con findAndModify, las comillas dobles $setno me funcionan. Tengo que usar comillas simples para el campo.
WesternGun
4

Puede usar la función updateOne de mongoDB pasando el índice del elemento en la matriz, si la clave del contenido antiguo B es "valor" por ejemplo:

[
...
"value" : "old content A"
"value" : "old content B"
"value" : "old content C"
...
]

el comando debería ser así:

db.collection.updateOne({"_id" : "...,"},{$set: {"my_array.1.value": "NEW content B"}})
Samuel Cabral
fuente
5
¿Cómo lo hacemos si no conocemos el índice?
Shaharyar Kirmani
3

Una forma ordenada de hacerlo en Javascript, con comillas invertidas, es:

 const index = 1;

 ...  {   $set: { [`myArray.${index}.value`]: "new content"}  },  ...
Ismael Soschinski
fuente
1

Cuando se requiere actualizar un elemento de matriz sin saber que es un índice real, pero que tiene un identificador único del elemento

db.getCollection('profiles').update(
  {
    'userId':'4360a380-1540-45d9-b902-200f2d346263',
    'skills.name':'css'
  },
  {
      $set: {'skills.$.proficiencyLevel': 5}
  }, 
  {
      multi: true
  }
)
Amarnathrao Sulake
fuente