Mongoose, zaktualizuj wartości w tablicy obiektów


101

Czy istnieje sposób na aktualizację wartości w obiekcie?

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

Powiedzmy, że chcę zaktualizować nazwy i wartości dla pozycji, gdzie id = 2;

Próbowałem następujących rzeczy w / mangusta:

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

Problem z tym podejściem polega na tym, że aktualizuje / ustawia cały obiekt, dlatego w tym przypadku tracę pole id.

Czy istnieje lepszy sposób w mongoose na ustawienie pewnych wartości w tablicy, ale pozostawienie innych wartości w spokoju?

Zapytałem również tylko o osobę:

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

Odpowiedzi:


169

Jesteś blisko; aby to zrobić, powinieneś użyć notacji z kropką podczas korzystania z $operatora aktualizacji :

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

Witam, kiedy zrobię dokładnie to zaproponowałeś. board.update ({_id: board._id, "users.username": req.user.username}, {$ set: {"users. $. lastViewed": new Date ()}}, function (err) {} ); Wystąpił błąd: nie mogę użyć części (users.username) do przejścia przez element ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), status: "zaproszeni", rola: " recenzent "}]}). Czy jest coś, co zrobiłem inaczej?
Peter Huang

6
To działa świetnie, dziękuję. Czy jest jednak sposób na utworzenie elementu, jeśli nie ma go w tablicy?
Sergey Mell

@SergeyMell, jeśli myślę, że to może być rozwiązanie: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

Jak zaktualizować nazwę dla id = 2 we wszystkich dokumentach w kolekcji?
Rod

1
Jak by to działało, gdybyś miał tablicę obiektów wewnątrz tablicy? Jak zamiast po prostu items.$.namemiałeś items.users.$.status? czy to zadziała?
Stevie Star


14

Jest na to sposób mangusty.

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

Ta metoda jest przydatna, jeśli wykonujesz operację na dokumencie nadrzędnym, a także na elemencie tablicy.
Jeremy

5

Dla każdego dokumentu operator aktualizacji $setmoże ustawić wiele wartości , więc zamiast zastępować cały obiekt w itemstablicy, można ustawić pola namei valueobiektu indywidualnie.

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

5

Jest jedna rzecz do zapamiętania, gdy szukasz obiektu w tablicy na podstawie więcej niż jednego warunku, użyj $ elemMatch

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

tutaj jest dokumentacja


4

Poniżej znajduje się przykład bardziej dynamicznego aktualizowania wartości w tablicy obiektów.

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

Zauważ, że robiąc to w ten sposób, byłbyś w stanie zaktualizować jeszcze głębsze poziomy zagnieżdżonej tablicy, dodając dodatkowy arrayFiltersoperator pozycyjny, taki jak ten:

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

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

Więcej zastosowań można znaleźć w oficjalnych dokumentach .


Fajnie, może proszę dodać link do oficjalnej dokumentacji na ten temat
Tayyab Ferozi


0

W mongoose możemy aktualizować, jak prosta tablica

user.updateInfoByIndex(0,"test")

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

4
Twoja odpowiedź byłaby bardziej pomocna z jakimś wyjaśnieniem. Prosimy o rozważenie edycji.
O. Jones,

0

W Mongoose możemy zaktualizować wartość tablicy za pomocą $setnotacji inside dot ( .) do określonej wartości w następujący sposób

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

Czy mógłbyś zmienić odpowiedź z objaśnieniami lub odnieść się do pytania?
NIKHIL CM

1
Czy mógłbyś rzucić okiem na moje pytanie, mongoose usuwa część mojego zapytania, która używa $ [], mimo że działa w
stosie

0

Wypróbowałem inne rozwiązania, które działały dobrze, ale pułapka ich odpowiedzi polega na tym, że tylko pola już istniejące będą aktualizować, dodając upsert, nic nie da, więc wymyśliłem to.

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

0

Miałem podobne problemy. Oto najczystszy sposób na zrobienie tego.

    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();
    });
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.