Mongoose, atualiza os valores em uma série de objetos


101

Existe uma maneira de atualizar valores em um objeto?

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

Digamos que eu queira atualizar os itens de nome e valor para o item onde id = 2;

Eu tentei o seguinte com mangusto:

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

O problema com esta abordagem é que ela atualiza / define todo o objeto, portanto, neste caso, eu perco o campo id.

Existe uma maneira melhor no mangusto de definir certos valores em uma matriz, mas deixar outros valores sozinhos?

Eu também consultei apenas a pessoa:

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().
});

Respostas:


169

Você está perto; você deve usar a notação de ponto ao usar o $operador de atualização para fazer isso:

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

Olá, quando eu fizer exatamente o que você sugeriu. board.update ({_id: board._id, "users.username": req.user.username}, {$ set: {"users. $. lastViewed": new Date ()}}, function (err) {} ); Recebi um erro: não é possível usar a parte (usuários de users.username) para atravessar o elemento ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), status: "convidado", função: " revisor "}]}). Existe algo que eu fiz de forma diferente?
Peter Huang

6
Isso funciona muito bem, obrigado. No entanto, existe alguma maneira de criar um item se ele não estiver na matriz?
Sergey Mell,

@SergeyMell se eu achar que pode ser uma solução: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

Como atualizo o nome de id = 2 em todos os documentos de uma coleção?
Rod

1
Como isso funcionaria se você tivesse uma matriz de objetos dentro de uma matriz? Tipo, em vez de apenas items.$.name, você tinha items.users.$.status? Isso funcionaria?
Stevie Star


14

Existe um jeito mangusto de fazer isso.

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 é útil se você estiver fazendo uma operação no documento pai, bem como no item da matriz.
Jeremy

5

Para cada documento, o operador de atualização $setpode definir vários valores , portanto, em vez de substituir o objeto inteiro na itemsmatriz, você pode definir os campos namee valuedo objeto individualmente.

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

5

Há uma coisa a lembrar, quando você está pesquisando o objeto no array com base em mais de uma condição, use $ elemMatch

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

aqui está a documentação


4

Abaixo está um exemplo de como atualizar o valor na matriz de objetos de forma mais dinâmica.

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

Observe que, fazendo isso dessa maneira, você seria capaz de atualizar níveis ainda mais profundos da matriz aninhada adicionando arrayFiltersoperadores adicionais e posicionais como:

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

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

Mais uso pode ser encontrado nos documentos oficiais .


Legal, talvez por favor, adicione um link para os documentos oficiais sobre isso
Tayyab Ferozi


0

No mongoose podemos atualizar, como array simples

user.updateInfoByIndex(0,"test")

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

4
Sua resposta seria mais útil com alguma explicação. Por favor, considere editá-lo.
O. Jones

0

No Mongoose, podemos atualizar o valor do array usando a notação $setdot ( .) para um valor específico da seguinte maneira

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

Você poderia editar a resposta com explicações ou relacionar-se com a pergunta?
NIKHIL CM de

1
Você poderia dar uma olhada na minha pergunta, mongoose está removendo a parte da minha consulta que usa $ [], embora funcione na CLI stackoverflow.com/questions/64223672/…
nrmad

0

Tendo tentado outras soluções que funcionaram bem, mas a armadilha de suas respostas é que apenas os campos já existentes atualizariam, adicionando upsert a ele não faria nada, então eu vim com isso.

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })

0

Eu tive problemas semelhantes. Esta é a maneira mais limpa de fazer isso.

    const personQuery = {
       _id: 1  
    }

    const itemID = 2;

    Person.findOne(personQuery).then(item => {
       const audioIndex = item.items.map(item => item.id).indexOf(itemID);
       item.items[audioIndex].name = 'Name value';
       item.save();
    });
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.