使用对象数组

时间:2016-12-16 08:58:21

标签: node.js mongodb express mongoose

我正在使用express.js服务器。我正在尝试更新mongodb集合中的现有文档使用mongoose 与对象数组(每个对象具有_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查询何时完成,然后才将响应从服务器发送回客户端。

mongoose中是否有任何替代方法可以一次编辑/修改对象数组然后调用回调?

注意* - 每个数组对象都有_id,它与文档_id值匹配。

3 个答案:

答案 0 :(得分:0)

是的,这很有可能。您可以利用批量写入API来处理异步操作,从而提高性能,尤其是处理大型数据集。对于支持>=4.3.0的Mongoose版本MongoDB Server 3.2.x, 您可以使用 bulkWrite() 进行更新。以下示例说明了如何解决此问题:

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

对于支持MongoDB服务器~3.8.8, ~3.8.22, 4.x的Mongoose版本>=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
    });
}

答案 1 :(得分:0)

解决方案是按for http://caolan.github.io/async/docs.html#each更改async.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.
});

答案 2 :(得分:0)

for (let i of expenseListToEdit) {
    Expense.findByIdAndUpdate(i._id, {})
    .exec()
    .then(function updated(expense) {
        if (expense) {
            //DO SMTH
        }
        }).then(null, function(err) {
            console.error(err)
            throw err;
        })
}