Mangosta, actualiza valores en una matriz de objetos


94

¿Hay alguna forma de actualizar los valores de un objeto?

{
  _id: 1,
  name: 'John Smith',
  items: [{
     id: 1,
     name: 'item 1',
     value: 'one'
  },{
     id: 2,
     name: 'item 2',
     value: 'two'
  }]
}

Digamos que quiero actualizar los elementos de nombre y valor para el elemento donde id = 2;

Probé lo siguiente con mangosta:

var update = {name: 'updated item2', value: 'two updated'};
Person.update({'items.id': 2}, {'$set':  {'items.$': update}}, function(err) { ...

El problema con este enfoque es que actualiza / configura todo el objeto, por lo tanto, en este caso, pierdo el campo de identificación.

¿Hay una mejor manera en la mangosta de establecer ciertos valores en una matriz pero dejar otros valores en paz?

También he consultado solo por la Persona:

Person.find({...}, function(err, person) {
  person.items ..... // I might be able to search through all the items here and find item with id 2 then update the values I want and call person.save().
});

Respuestas:


162

Estás cerca; debe usar la notación de puntos en su uso del $operador de actualización para hacer eso:

Person.update({'items.id': 2}, {'$set': {
    'items.$.name': 'updated item2',
    'items.$.value': 'two updated'
}}, function(err) { ...

Hola, cuando hago exactamente lo que sugieres. board.update ({_id: board._id, "users.username": req.user.username}, {$ set: {"users. $. lastViewed": new Date ()}}, function (err) {} ); Recibí un error: no puedo usar la parte (usuarios de users.username) para atravesar el elemento ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), estado: "invitado", rol: revisor "}]}). ¿Hay algo que hice de manera diferente?
Peter Huang

4
Esto funciona muy bien, gracias. Sin embargo, ¿hay alguna forma de crear un elemento si no está en la matriz?
Sergey Mell

@SergeyMell si creo que podría ser una solución: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

¿Cómo actualizo el nombre de id = 2 en todos los documentos de una colección?
Rod

1
¿Cómo funcionaría esto si tuviera una matriz de objetos dentro de una matriz? ¿Como en lugar de solo items.$.name, tuviste items.users.$.status? ¿Funcionaría eso?
Stevie Star


12

Hay una forma de mangosta para hacerlo.

const itemId = 2;
const query = {
  item._id: itemId 
};
Person.findOne(query).then(doc => {
  item = doc.items.id(itemId );
  item["name"] = "new name";
  item["value"] = "new value";
  doc.save();

  //sent respnse to client
}).catch(err => {
  console.log('Oh! Dark')
});

Este método es útil si está realizando una operación en el documento principal y en el elemento de la matriz.
Jeremy

5

Para cada documento, el operador de actualización $setpuede establecer varios valores , por lo que en lugar de reemplazar todo el objeto en la itemsmatriz, puede establecer los campos namey valuedel objeto individualmente.

{'$set':  {'items.$.name': update.name , 'items.$.value': update.value}}

3

Hay una cosa para recordar, cuando busca el objeto en la matriz sobre la base de más de una condición, use $ elemMatch

Person.update(
   {
     _id: 5,
     grades: { $elemMatch: { grade: { $lte: 90 }, mean: { $gt: 80 } } }
   },
   { $set: { "grades.$.std" : 6 } }
)

aquí están los documentos



2

A continuación se muestra un ejemplo de cómo actualizar el valor en la matriz de objetos de forma más dinámica.

Person.findOneAndUpdate({_id: id}, 
{ 
  "$set": {[`items.$[outer].${propertyName}`]: value} 
},
{ 
  "arrayFilters": [{ "outer.id": itemId }]
},
function(err, response) {
  ...
})

Tenga en cuenta que al hacerlo de esa manera, podrá actualizar niveles aún más profundos de la matriz anidada agregando adicionales arrayFilterscomo:

"$set": {[`items.$[outer].innerItems.$[inner].${propertyName}`]: value} 

"arrayFilters":[{ "outer.id": itemId },{ "inner.id": innerItemId }]

Espero que ayude. ¡Buena suerte!


0

En mangosta podemos actualizar, como una matriz simple

user.updateInfoByIndex(0,"test")

User.methods.updateInfoByIndex = function(index, info) ={
    this.arrayField[index]=info
    this.save()
}

4
Su respuesta sería más útil con alguna explicación. Considere editarlo.
O. Jones

0

En Mongoose, podemos actualizar el valor de la matriz usando la notación $setdentro de dot ( .) a un valor específico de la siguiente manera

db.collection.update({"_id": args._id, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}})

¿Podría editar la respuesta con explicaciones o relacionarse con la pregunta?
NIKHIL CM

1
¿Podrías echarle un vistazo a mi pregunta? Mongoose está eliminando la parte de mi consulta que usa $ [] a pesar de que funciona en la CLI stackoverflow.com/questions/64223672/…
nrmad

0

Después de haber probado otras soluciones que funcionaron bien, pero el problema de sus respuestas es que solo los campos ya existentes se actualizarían y agregaron upsert no harían nada, así que se me ocurrió esto.

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.