การอัปเดตเอกสารหลายรายการโดยใช้อาร์เรย์ของวัตถุ

ฉันใช้เซิร์ฟเวอร์ express.js ฉันกำลังพยายามอัปเดตเอกสารที่มีอยู่ในคอลเลกชัน mongodb โดยใช้พังพอน ด้วยอาร์เรย์ของวัตถุ (แต่ละวัตถุมีคุณสมบัติ _id และค่าของมันสอดคล้องกับแต่ละเอกสาร _id)

วิธีหนึ่งคือการวนซ้ำผ่านอาร์เรย์และดำเนินการ findByIdAndUpdate()

for(var i=0; i < expenseListToEdit.length; i++) {    
    var expense = expenseListToEdit[i];

    Expense.findByIdAndUpdate(expense._id, expense, function(err, model) {
        if (err) {    
            console.log('Error occurred while editing expense');
        }

        console.log('model: ' + util.inspect(model));
    });
}

แต่ด้วยวิธีนี้ ฉันจะต้องจัดการกับสถานการณ์แบบอะซิงโครนัส และจะต้องตรวจสอบว่าเมื่อใดที่การสืบค้น db สำหรับการวนซ้ำทั้งหมดเสร็จสิ้น จากนั้นจึงส่งเฉพาะการตอบกลับไปยังไคลเอนต์จากเซิร์ฟเวอร์เท่านั้น

มีวิธีอื่นในพังพอนในการแก้ไข / แก้ไขอาร์เรย์ของวัตถุในครั้งเดียวแล้วโทรกลับหรือไม่?

หมายเหตุ*- แต่ละออบเจ็กต์อาร์เรย์มี _id ปัจจุบัน ซึ่งตรงกับค่าเอกสาร _id


person Abhijeet Srivastava    schedule 16.12.2016    source แหล่งที่มา


คำตอบ (3)


ใช่ มันค่อนข้างเป็นไปได้ คุณสามารถใช้ประโยชน์จากการใช้ API การเขียนจำนวนมากเพื่อจัดการการดำเนินการอะซิงก์และทำให้มีประสิทธิภาพดีขึ้น โดยเฉพาะอย่างยิ่งการจัดการกับชุดข้อมูลขนาดใหญ่ สำหรับ Mongoose เวอร์ชัน >=4.3.0 ที่รองรับ MongoDB Server 3.2.x คุณสามารถใช้ _3 สำหรับการอัปเดต ตัวอย่างต่อไปนี้แสดงวิธีการดำเนินการนี้:

var bulkUpdateCallback = function(err, r){
    console.log(r.matchedCount);
    console.log(r.modifiedCount);
}
// Initialise the bulk operations array
var bulkOps = expenseListToEdit.map(function (expense) { 
    return { 
        "updateOne": { 
            "filter": { "_id": expense._id } ,              
            "update": { "$set": expense } 
        }         
    }    
});

// Get the underlying collection via the native node.js driver collection object
Expense.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback);

สำหรับ Mongoose เวอร์ชัน ~3.8.8, ~3.8.22, 4.x ซึ่งรองรับ MongoDB Server >=2.6.x คุณสามารถใช้ Bulk API ดังนี้

var bulk = Expense.collection.initializeOrderedBulkOp(),
    counter = 0;

expenseListToEdit.forEach(function(expense) {
    bulk.find({ "_id": expense._id })
        .updateOne({ "$set": expense });

    counter++;
    if (counter % 500 == 0) {
        bulk.execute(function(err, r) {
           // do something with the result
           bulk = Expense.collection.initializeOrderedBulkOp();
           counter = 0;
        });
    }
});

// Catch any docs in the queue under or over the 500's
if (counter > 0) {
    bulk.execute(function(err, result) {
       // do something with the result here
    });
}
person chridam    schedule 16.12.2016

วิธีแก้ไขคือเปลี่ยนคำสั่ง for ด้วย async.each http://caolan.github.io/async/docs.html#each :

คำเตือน : แต่ละการเปิดตัวองค์ประกอบทั้งหมดขนานกัน

async.each(expenseListToEdit, function (expense, done) {
    Expense.findByIdAndUpdate(expense._id, expense, function(err, model) {
        if (err) {    
           console.log('Error occurred while editing expense');
           done(err); // if an error occured, all each is stoped
           return;
        }

        console.log('model: ' + util.inspect(model));
        done();
    });
}, function (err) {
    // final callback launched after all findByIdAndUpdate calls.
});
person throrin19    schedule 16.12.2016

person    schedule
comment
โปรดลองเพิ่มคำอธิบายเกี่ยวกับวิธีการทำงานของโค้ดนี้และเหตุผล อาจมีลิงก์ไปยังเอกสารประกอบ - person dheiberg; 25.07.2017