关于Nodejs async parallel的问题

关于Nodejs async parallel的问题

现在我有一个数组,包含一组id, 然后用mongoose去查询更新数据

var ids = [1,2,3,4,5];
var successLen = 0;
ids.forEach(function(id) {
merchandiseModel.findByIdAndUpdate(id, {
$inc: {
order_num: 2
}
},
function(err, numberAffected, rawResponse) {

	if(err){
		console.error(err.message);
        return;				
	}
	if(numberAffected == 1)
 		successLen++;
});
}

用async如何去获取最后更新的成功数successLen?


10 回复

现在我有一个数组,包含一组id, 然后用mongoose去查询更新数据 var ids = [1,2,3,4,5]; var successLen = 0; ids.forEach(function(id) { merchandiseModel.findByIdAndUpdate(id, { $inc: { order_num: 2 } }, function(err, numberAffected, rawResponse) {

	if(err){
		console.error(err.message);
        return;				
	}
	if(numberAffected == 1)
 		successLen++;
});

} 用async如何去获取最后更新的成功数successLen?


async.inject(ids, 0, function (successLen, id, callback) {
  Model.findByIdAndUpdate(id, update, function (err, Model) {
    if (err) return callback(err)
    callback(null, ++successLen)
  })
},

function (err, successLen) {
  if (err) return // handle err...
  console.log('successLen', successLen)
})

這樣寫會不會更簡單些:

Model.update(conditions, update, { multi: true }, function (err, numberAffected) {
  if (err) return // handle err...
  console.log('numberAffected', numberAffected)
})

參考討論看看。 :)

多谢,不过,你上面的有点问题,如果if(err)满足条件 callback(err),这样会导致立马执行最后一个函数,接下来的id不会再执行了. Model.update的话,如果是一个很大的数组,然后update的值是各不相同的,这个怎么写?比如数据: data = [{id: 1, num: 123}, {id:2, num: 321}…] 现在根据data数组的id去查找数据,找到后更新num,如何根据data写conditions,update?

如果不要 break loop 那就是用 async.each 了:

var successLen = 0

async.each(ids, function (id, callback) { Model.findByIdAndUpdate(id, update, function (err, numberAffected) { if (err) return callback(err) if (numberAffected === 1) successLen++ callback(null) }) },

function (err) { if (err) return // handle err console.log(‘successLen’, successLen) })

丟一個 successLen 在外部我覺得這樣寫好醜,不曉得有沒有更漂亮的寫法。

Model.update 依不同 id 寫入不同 data 應該沒有辦法用一條簡單的條件句,可能一定得要用 loop 完成。

async好像只要调用callback(err)就会立刻中断, 最后我还是用你的async.inject处理的,不调用callback(err)就好 if(err) callback(null, successLen)

[@asfman](/user/asfman)

async.each 碰到 callback(err) 不會中斷吧?

async.each 最後的 callback 有兩種情況會被觸發:

  • 當錯誤發生時,也就是 callback(err) 有傳入值進去
  • 所有 iterator 完成時

值得注意的是,當發生 err 時第二個情況不會執行。示意:

async.each([1, 2, 3], function (item, done) {
  console.log('item', item)
  if (item === 2) return done(item)
  done(null)
},

function (err) { if (err) return console.log(‘err’, err) console.log(‘done’) })

// item 1 // item 2 // err 2 // item 3

async.each([1, 2, 3], function (item, done) {
console.log(‘item’, item)
done(null)
},

function (err) { if (err) return console.log(‘err’, err) console.log(‘done’) })

// item 1 // item 2 // item 3 // done

[@chinghanho](/user/chinghanho) each果然会都执行一遍,我看到文档里的 >the main callback (for the each function) is immediately called with the error. 以为执行了main callback就表示结束了…,不过要统计成功的数目,还是用inject优雅点

[@chinghanho](/user/chinghanho) 赞答案 [@asfman](/user/asfman) 确实用 inject 更符合函数式编程的思想。但代码上来说的话,.each 应该优雅点吧?多个 count 变量而已。

在使用 Node.js 和 Mongoose 进行批量更新时,async 库中的 parallel 方法可以帮助你并行执行多个异步操作。这不仅可以提高效率,还能更清晰地组织代码。下面是如何使用 async.parallel 来处理你的需求,并获取最终成功更新的数量。

示例代码

首先,确保你已经安装了 async 库:

npm install async

然后,你可以按照以下方式重构你的代码:

const async = require('async');
const mongoose = require('mongoose');

// 假设 merchandiseModel 是你的 Mongoose 模型
const merchandiseModel = mongoose.model('Merchandise', new mongoose.Schema({}));

var ids = [1, 2, 3, 4, 5];
var successCount = 0;

async.parallel(
    ids.map(id => callback => 
        merchandiseModel.findByIdAndUpdate(id, 
            { $inc: { order_num: 2 } }, 
            { new: true }, // 确保返回更新后的文档
            (err, doc) => {
                if (err) {
                    console.error(err.message);
                    callback(err); // 将错误传递给 async
                    return;
                }
                if (doc) {
                    successCount++;
                }
                callback(null, doc); // 成功时调用 callback 并传入结果
            }
        )
    ),
    (err, results) => {
        if (err) {
            console.error("An error occurred:", err);
            return;
        }
        console.log(`Total successful updates: ${successCount}`);
        // results 包含每个异步操作的结果
    }
);

解释

  1. async.parallel: 该函数接受两个参数:一个任务数组和一个回调函数。任务数组中的每个元素都是一个函数,该函数接收一个 callback 函数作为参数。

  2. ids.map: 使用 map 方法遍历 ids 数组,并为每个 id 创建一个任务。每个任务是一个函数,它调用 findByIdAndUpdate 方法来更新数据库。

  3. findByIdAndUpdate: 这个方法用于查找文档并更新它。我们传递 { new: true } 参数以确保返回更新后的文档,而不是原始文档。

  4. callback: 在 findByIdAndUpdate 的回调中,我们检查是否有错误发生。如果有错误,则通过 callback(err) 传递错误。如果更新成功,我们增加 successCount 计数器。

  5. 最终的回调: 当所有并行任务完成后,async.parallel 的第二个参数将被调用。此时,results 参数包含了每个任务的结果。你可以在这里处理这些结果或进行其他清理工作。

这种方法不仅使代码更简洁、更易读,而且利用了 async.parallel 的能力来高效地并行执行多个异步操作。

在使用 async 库中的 parallel 方法来处理多个异步操作时,可以将每个更新操作放入一个函数中,然后使用 async.parallel 来并行执行这些函数。最终,通过回调函数来获取所有更新操作的结果,并计算成功更新的数量。

以下是一个示例代码:

const async = require('async');
const mongoose = require('mongoose');

// 假设 merchandiseModel 已经定义好
const merchandiseModel = mongoose.model('Merchandise', new mongoose.Schema({}));

var ids = [1, 2, 3, 4, 5];
var successLen = 0;

var tasks = ids.map(id => {
    return function(callback) {
        merchandiseModel.findByIdAndUpdate(id, {
            $inc: {
                order_num: 2
            }
        }, function(err, numberAffected) {
            if (err) {
                console.error(err.message);
                return callback(err);
            }
            callback(null, numberAffected === 1);
        });
    };
});

async.parallel(tasks, function(err, results) {
    if (err) {
        console.error(err.message);
        return;
    }

    successLen = results.filter(Boolean).length;
    console.log(`Success updates: ${successLen}`);
});

解释

  1. 定义任务数组

    • 使用 ids.map 创建一个任务数组,其中每个任务是一个函数,该函数使用 findByIdAndUpdate 更新文档,并在回调中传递结果。
  2. 执行并行任务

    • 使用 async.parallel 并行执行所有任务。
  3. 处理结果

    • async.parallel 的回调函数中,results 是一个布尔值数组,表示每个更新是否成功。
    • 使用 results.filter(Boolean).length 计算成功更新的数量。

这样就可以并行地执行多个更新操作,并统计成功更新的数量。

回到顶部