Мангуст, оновлення значень у масиві об’єктів


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 ()}}, функція (помилка) {} ); Я отримав помилку: не можу використовувати частину (користувачі users.username) для обходу елемента ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), статус: "запрошений", роль: " рецензент "}]}). Чи є щось, що я робив інакше?
Пітер Хуан,

4
Це чудово працює, дякую. Однак чи є спосіб створити елемент, якщо його немає в масиві?
Сергій Мелл

@SergeyMell, якщо я думаю, що це може бути рішенням: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

Як оновити ім'я для id = 2 у всіх документах колекції?
Род

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 ми можемо оновити значення масиву, використовуючи нотацію $setdot ( .) до конкретного значення наступним чином

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.