Mongoose, обновить значения в массиве объектов


94

Есть ли способ обновить значения в объекте?

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

Допустим, я хочу обновить элементы имени и значения для элемента, где id = 2;

Я пробовал следующее с мангустом:

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

Проблема с этим подходом в том, что он обновляет / устанавливает весь объект, поэтому в этом случае я теряю поле id.

Есть ли лучший способ в мангусте установить определенные значения в массиве, но оставить другие значения в покое?

Я также запросил только человека:

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

Ответы:


162

Вы близко; вы должны использовать точечную нотацию при использовании $оператора обновления для этого:

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

Привет, когда я это сделаю, именно ты предложил. board.update ({_id: board._id, "users.username": req.user.username}, {$ set: {"users. $. lastViewed": new Date ()}}, function (err) {} ); Я получил ошибку: не могу использовать часть (users of users.username) для перемещения по элементу ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), status: "selected", role: " рецензент "}]}). Что-нибудь я сделал иначе?
Питер Хуанг

4
Это отлично работает, спасибо. Однако есть ли способ создать элемент, если его нет в массиве?
Сергей Мелл

@SergeyMell, если я думаю, что это может быть решение: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

Как мне обновить имя для id = 2 во всех документах коллекции?
Rod

1
Как бы это работало, если бы у вас был массив объектов внутри массива? Вроде, а не просто у items.$.nameтебя items.users.$.status? это сработает?
Стиви Стар


12

Есть способ сделать это мангустом.

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')
});

Этот метод удобен, если вы выполняете операцию как с родительским документом, так и с элементом массива.
Джереми

5

Для каждого документа оператор обновления $setможет установить несколько значений , так что вместо того , чтобы заменить весь объект в itemsмассиве, вы можете установить nameи valueполе объекта индивидуальны.

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

3

Следует помнить одну вещь: когда вы ищете объект в массиве на основе более чем одного условия, используйте $ elemMatch

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

вот документы



2

Ниже приведен пример более динамичного обновления значения в массиве объектов.

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

Обратите внимание, что, сделав это таким образом, вы сможете обновить еще более глубокие уровни вложенного массива, добавив дополнительные, arrayFiltersнапример:

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

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

Я надеюсь, что это помогает. Удачи!


0

В мангусте мы можем обновлять, как простой массив

user.updateInfoByIndex(0,"test")

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

4
Ваш ответ был бы более полезным с некоторыми пояснениями. Пожалуйста, рассмотрите возможность его редактирования.
O. Jones

0

В Mongoose мы можем обновить значение массива, используя $setвнутреннюю .нотацию dot ( ), до определенного значения следующим образом

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

Не могли бы вы отредактировать ответ с пояснениями или связать с вопросом?
NIKHIL CM

1
Не могли бы вы взглянуть на мой вопрос, мангуст удаляет часть моего запроса, который использует $ [], хотя он работает в CLI stackoverflow.com/questions/64223672/…
nrmad

0

Попробовав другие решения, которые работали нормально, но подводный камень их ответов заключается в том, что только существующие поля будут обновляться, добавление к нему upsert ничего не сделает, поэтому я придумал это.

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.