async.forEach:在执行每个任务之前调用最终回调

时间:2017-10-02 06:18:15

标签: node.js mongodb asynchronous

我在mongodb数据库中有一个用户架构(我通过mongoose处理)。我想通过网页通过客户端提供的值更新用户的详细信息。详情如下:

我们有一个mongoose模式User,它有一个名为authorities []的属性,即每个用户可以拥有多个称为权限的对象类型。 userSchema如下所示:

`

var UserSchema = Schema({
      name: {type: String, required: true, max: 50},
      username:{type: String, required: true, unique: true, max: 30},
      password:{type: String, required: true, max: 30},
      authorities:[{type: Schema.ObjectId, ref: 'Authority'}],
      mobileNo:{type: Number},
      superadmin:{type: Boolean, default: false}
    });

`

每个管理局都有一个ID和一个名字,如下所示:

`

var AuthoritySchema = Schema({
    name: {type: String, required: true, max: 100}
  });

`

管理员从客户端网页发送POST请求中的更新值。我们希望找到用户,然后使用客户提供的值更新数据库中的值。

网页代码的相关部分如下:

`

var url = "/db/users/edit?token=" + token; // constructing the url for post operation
 var params = {"token": token, "userId": user_id, "userName": user_name, "authorities": auth_list.toString(), "superadmin": admin_status}; // constructing the params for post operation
 $.post(url, params, function(data, status){
   alert(data);
 });

`

处理此调用的路由器功能如下:

`

/* POST for editing a user */
router.post('/users/edit', function (req, res, next){
  console.log('Inside db router edit user function with decoded request = ' + req.decoded.sub + ' and request user_id as ' + req.body.userId+ ' and request userName as '+req.body.userName+ ' and authorities as ' + req.body.authorities + ' and admin status as ' + req.body.superadmin);
  if (req.decoded.su){
    next();
  } else{
    res.render('index', {title: 'Home Page', errors: [{msg: 'You don\'t have the privileges to access the page.'}]});
  }
}, user_controller.user_update_post);

`

控制器中的相关功能如下:

`

// Handle User update on POST
exports.user_update_post = function(req, res) {
    console.log("inside user controller.update_post");
    var auth_name_array = req.body.authorities.split(","); // We get the authority names in a string in req.body.authorities and split it on commas here
    var auth_id_array = []; // We want to find the corresponding authority ids because the userSchema takes an array of ids in the authority field and not authority names. We will use this array to store them in. We want to store all authority ids in this array and only then pass the full array on to the findByIdAndUpdate function that is why using async.forEach
    async.forEach(auth_name_array, function(auth_name, callback){
      Authority.find({'name': auth_name}, '_id', function(err, authId){ // We find the corresponding authority in the database and return its id
          if (err) res.send(err);
          console.log("authId: " + authId); // The id is fetching properly and output is good
          auth_id_array.push(authId); // We store the id in our array
          console.log("auth_id_array.length is now " + auth_id_array.length); // The id is added properly and array length is incrementing by 1 with each push
          });      
      callback();
    }, function(err){
      if (err) res.send(err);
      console.log("here to update the record with auth_id_array.length as " + auth_id_array.length); // However, here array length is shown as 0 and the authorities supplied by client are not getting updated in database. This part of the code is seeing an empty array
      User.findByIdAndUpdate(req.body.userId, {$set: {name: req.body.userName, superadmin: req.body.superadmin, authorities: auth_id_array}}, function(err, result){
        if (err) res.send(err);
        res.send(result);
      });
    });
};

` 问题在于,即使正确获取了权限ID并将其推送到auth_id_array,也会在将auth_id_array传递给findByIdAndUpdate数据库操作之后发生。这是违反直觉的,因为这段代码在最终回调中,并且应该在每个async.forEach任务运行之后运行。用于备份它的控制台输出如下:

Inside db router edit user function with decoded request = admin and request user_id as 59cf64989cbff357fc3b85aa and request userName as Mummy10 and authorities as SDO Bali,Revenue,Miscllaneous and admin status as true
inside user controller.update_post
here to update the record with auth_id_array.length as 0
authId: { _id: 59c4ea3efaebb61c19af9432 }
auth_id_array.length is now 1
authId: { _id: 59c4ea8933294b1c2f1962ee }
auth_id_array.length is now 2
authId: { _id: 59c4eaa165ccc01c3c7bc07e }
auth_id_array.length is now 3

请参阅控制台输出的第三行。它应该在获取所有权限ID并将其推送到阵列后打印。

请帮忙!自48小时以来我一直坚持这个!这是我最后的希望。

1 个答案:

答案 0 :(得分:1)

您在调用callback的回叫之前调用Authority.find()。而是将呼叫转移到其中的callback

Authority.find({'name': auth_name}, '_id', function(err, authId){ // We find the corresponding authority in the database and return its id
    if (err) return callback(err);
    console.log("authId: " + authId); // The id is fetching properly and output is good
    auth_id_array.push(authId); // We store the id in our array
    console.log("auth_id_array.length is now " + auth_id_array.length); // The id is added properly and array length is incrementing by 1 with each push
    callback();
});      

注意发生错误时它如何调用callback(err)

最后回调中的其他一些问题:

if (err) res.send(err);

发送回复后,请确保您实际停止运行以下代码。你可以通过返回:

来做到这一点
if (err) return res.send(err);

同样的问题:

  User.findByIdAndUpdate(req.body.userId, {$set: {name: req.body.userName, superadmin: req.body.superadmin, authorities: auth_id_array}}, function(err, result){
    if (err) res.send(err);
    res.send(result);
  });

应该是:

if (err) res.send(err)
else res.send(result);

或者:

if (err) return res.send(err);
res.send(result);

最后:因为您要在async.forEach"循环"中构建数组,您还可以使用async.map()