พังพอนอัปเดตค่าในอาร์เรย์ของวัตถุ


94

มีวิธีอัพเดตค่าในออบเจ็กต์หรือไม่?

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

สมมติว่าฉันต้องการอัปเดตชื่อและรายการค่าสำหรับรายการที่ id = 2;

ฉันได้ลองใช้ w / พังพอนต่อไปนี้:

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.username) เพื่อสำรวจองค์ประกอบ ({ผู้ใช้: [{ชื่อผู้ใช้: "nlm", _id: ObjectId ('583c8cc3813daa6c29f69cb0'), สถานะ: "เชิญ", บทบาท: " reviewer "}]}) มีอะไรที่ฉันทำแตกต่างออกไปหรือไม่?
Peter Huang

4
มันใช้งานได้ดีขอบคุณ อย่างไรก็ตามมีวิธีใดบ้างในการสร้างไอเท็มหากไม่ได้อยู่ในอาร์เรย์
Sergey Mell

@SergeyMell ถ้าฉันคิดว่านั่นอาจจะเป็นทางออก: stackoverflow.com/a/33577318/6470918
Grzegorz Brzęczyszczykiewicz

ฉันจะอัปเดตชื่อสำหรับ id = 2 ในเอกสารทั้งหมดในคอลเล็กชันได้อย่างไร
Rod

1
สิ่งนี้จะทำงานอย่างไรถ้าคุณมีอาร์เรย์ของวัตถุภายในอาร์เรย์ ชอบแทนที่จะเป็นเพียงitems.$.nameคุณมีitems.users.$.status? จะได้ผลไหม
Stevie Star


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

วิธีนี้มีประโยชน์หากคุณกำลังดำเนินการกับเอกสารหลักรวมทั้งรายการอาร์เรย์
Jeremy

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

ในพังพอนเราสามารถอัปเดตค่าอาร์เรย์โดยใช้สัญกรณ์$setภายในจุด ( .) เป็นค่าเฉพาะได้ด้วยวิธีต่อไปนี้

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

คุณช่วยแก้ไขคำตอบพร้อมคำอธิบายหรือเกี่ยวข้องกับคำถามได้ไหม
NIKHIL CM

1
คุณช่วยดูคำถามของฉันได้ไหมพังพอนกำลังลบส่วนของข้อความค้นหาของฉันซึ่งใช้ $ [] แม้ว่าจะใช้งานได้ใน CLI stackoverflow.com/questions/64223672/…
nrmad

0

เมื่อลองใช้วิธีแก้ปัญหาอื่น ๆ ที่ใช้งานได้ดี แต่ข้อผิดพลาดของคำตอบคือเฉพาะฟิลด์ที่มีอยู่แล้วเท่านั้นที่จะอัปเดตการเพิ่มข้อมูลที่เพิ่มเข้ามาจะไม่ทำอะไรเลยดังนั้นฉันจึงคิดสิ่งนี้ขึ้นมา

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.