Mongoose, cập nhật giá trị trong mảng đối tượng


94

Có cách nào để cập nhật giá trị trong một đối tượng không?

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

Giả sử tôi muốn cập nhật tên và giá trị các mục cho mục có id = 2;

Tôi đã thử w / mongoose sau:

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

Vấn đề với cách tiếp cận này là nó cập nhật / thiết lập toàn bộ đối tượng, do đó, trong trường hợp này, tôi mất trường id.

Có cách nào tốt hơn trong mongoose để đặt các giá trị nhất định trong một mảng nhưng để lại các giá trị khác không?

Tôi cũng đã truy vấn chỉ Người:

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

Câu trả lời:


162

Bạn đang ở gần; bạn nên sử dụng ký hiệu dấu chấm khi sử dụng $toán tử cập nhật để thực hiện điều đó:

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

Xin chào, khi tôi làm đúng như bạn đề xuất. board.update ({_id: board._id, "users.username": req.user.username}, {$ set: {"users. $. lastViewed": new Date ()}}, function (err) {} ); Tôi gặp lỗi: không thể sử dụng phần (người dùng của users.username) để xem qua phần tử ({users: [{username: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), trạng thái: "được mời", vai trò: " người đánh giá "}]}). Có điều gì tôi đã làm khác đi không?
Peter Huang,

4
Điều này làm việc tuyệt vời, cảm ơn bạn. Tuy nhiên, có cách nào để tạo một mục nếu nó không có trong mảng?
Sergey Mell

@SergeyMell nếu tôi nghĩ rằng có thể là một giải pháp: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

Làm cách nào để cập nhật tên cho id = 2 trong tất cả các tài liệu trong bộ sưu tập?
Rod

1
Điều này sẽ hoạt động như thế nào nếu bạn có một mảng các đối tượng bên trong một mảng? Thay vì chỉ items.$.name, bạn đã có items.users.$.status? Liệu điều đó có hiệu quả?
Stevie Star


12

Có một cách mongoose để làm điều đó.

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

Phương pháp này rất hữu ích nếu bạn đang thực hiện một thao tác trên tài liệu mẹ cũng như mục mảng.
Jeremy

5

Đối với mỗi tài liệu, toán tử cập nhật $setcó thể đặt nhiều giá trị , vì vậy thay vì thay thế toàn bộ đối tượng trong itemsmảng, bạn có thể đặt các trường namevaluecủa đối tượng riêng lẻ.

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

3

Có một điều cần nhớ, khi bạn đang tìm kiếm đối tượng trong mảng trên cơ sở nhiều hơn một điều kiện thì hãy sử dụng $ elemMatch

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

đây là tài liệu



2

Dưới đây là ví dụ về cách cập nhật giá trị trong mảng đối tượng một cách linh động hơn.

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

Lưu ý rằng bằng cách làm theo cách đó, bạn sẽ có thể cập nhật các cấp độ sâu hơn của mảng lồng nhau bằng cách thêm bổ sung arrayFiltersnhư vậy:

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

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

Tôi hy vọng nó sẽ giúp. Chúc may mắn!


0

Trong mongoose, chúng ta có thể cập nhật, như mảng đơn giản

user.updateInfoByIndex(0,"test")

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

4
Câu trả lời của bạn sẽ hữu ích hơn với một số giải thích. Vui lòng xem xét chỉnh sửa nó.
O. Jones

0

Trong Mongoose, chúng ta có thể cập nhật giá trị mảng bằng ký hiệu $setbên trong dấu chấm ( .) thành giá trị cụ thể theo cách sau

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

Bạn vui lòng chỉnh sửa câu trả lời kèm theo lời giải thích hoặc liên quan đến câu hỏi?
NIKHIL CM

1
Bạn có thể xem qua câu hỏi của tôi không, mongoose đang xóa phần truy vấn của tôi sử dụng $ [] mặc dù nó hoạt động trong CLI stackoverflow.com/questions/64223672/…
nrmad

0

Đã thử các giải pháp khác hoạt động tốt, nhưng cạm bẫy của câu trả lời của họ là chỉ có các trường đã tồn tại sẽ cập nhật việc bổ sung thêm vào nó sẽ không làm gì cả, vì vậy tôi đã nghĩ ra điều này.

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.