0

I am having Array of Objects i.e users and I am using async.parallel inside async.each. Now, I didn't get back response in async.each. My code is as follows:

exports.addUserByCSV = function (req, res) {


  var users = req.body;
  async.each(users,
    function (user, callback) {
      var user = new User({
        username: user.email,
        password: user.email.split('@')[0],
        ipAddress: req.ip,
        firstname: user.firstname,
        lastname: user.lastname,
        email: user.email,
        employeeCode: user.employeeCode,
        dateOfJoining: user.dateOfJoining,
        dateOfAnniversary: user.dateOfAnniversary,
        dateOfBirth: user.dateOfBirth,
        employeeStatus: user.employeeStatus,
        iw: user.iw,
        fatherName: user.fatherName,
        aliasName: user.aliasName,
        aliasEmail: user.aliasEmail,
        panNo: user.panNo,
        gender: user.gender,
        maritalStatus: user.maritalStatus,
        biometricId: user.biometricId,
        shift: user.shift,
        nextApprisalDate: user.nextApprisalDate,
        esiNo: user.esiNo,
        pfNo: user.pfNo,
        bankAccNo: user.bankAccNo,
        situtation: user.situtation,
        phone: user.phone,
        mobile: user.mobile,
        fax: user.fax,
        website: user.website,
        address: user.address,
        city: user.city,
        state: user.state,
        zip: user.zip,
        country: user.country
      });
      userAdd(user, function (err, user) {
        console.log(user)
        callback(err);
      });
    },
    function (err) {
      res.send({ error: err, message: config.msg.SUCCESSFULLY_ADDED, user: 'User create Successfully' });
    }
  );
  function userAdd(user) {
    //console.log(user)
    user.register(user, function (err, user) {
      async.parallel({

        leave: function (callback) {
          //add some leaves for user
          _availLeaves(req.ID, user._id, function (err, leaves) {
            callback(err, leaves);
          });
        },
        salary: function (callback) {
          //add salary structure for employee
          _salaryStructure(req.ID, user._id, function (err, structure) {
            callback(err, structure);
          });
        }
      }, function (err, results) {
        console.log(results)
        if (!err) { return results; }

        res.send({ error: err, message: config.msg.SUCCESSFULLY_ADDED, user: 'User create Successfully' });

      });

    });
  }

}

function _salaryStructure(loginId, userId, cb) {
  var structure = new Structure({
    userId: userId,
    addedBy: loginId,
  });
  structure.save(function (err, structure) {
    cb(err, structure);
  });
}
function _availLeaves(loginId, userId, cb) {
  var leave = new LeaveAvailable({
    "userId": userId,
    "bl": 0.50,
    "fl": 2,
    "cl": 1,
    "pl": (new Date().getDate() <= 15) ? 0.75 : 0
  });

  leave.save(function (err, leaves) {
    cb(err, 'leavesAdded')
  });
}

If I write res.send in async.parallel then I got following issue :

Error: Can't set headers after they are sent.

If I write res.send in async.each then I didn't get any response.

Manan Vaghasiya
  • 881
  • 1
  • 10
  • 25
GsMalhotra
  • 1,837
  • 3
  • 14
  • 22
  • I don't know if this is a typo or if this is the source of your bug but `function userAdd(user)` <-- where is the callback? It should be `function userAdd(user,callback){...` – slebetman Feb 21 '17 at 12:06

2 Answers2

0

The problem is, that you are calling res.send for each user and thus multiple times. Instead you could combine res.write (each time) with a res.end (after all users have been written).

Have a look at this for more details.

So your updated code could look like this:

exports.addUserByCSV = function(req, res) {


    var users=req.body;
    async.each(users,

  function(user, callback){
     var user = new User({
        username: user.email,
        password: user.email.split('@')[0],
        ipAddress: req.ip,
        firstname: user.firstname,
        lastname: user.lastname,
        email: user.email,
        employeeCode: user.employeeCode,
        dateOfJoining:user.dateOfJoining,
        dateOfAnniversary:user.dateOfAnniversary,
        dateOfBirth:user.dateOfBirth,
        employeeStatus: user.employeeStatus,
        iw: user.iw,
        fatherName:user.fatherName,
        aliasName:user.aliasName,
        aliasEmail:user.aliasEmail,
        panNo:user.panNo,
        gender:user.gender,
        maritalStatus:user.maritalStatus,
        biometricId:user.biometricId,
        shift:user.shift,
        nextApprisalDate:user.nextApprisalDate,
        esiNo:user.esiNo,
        pfNo:user.pfNo,
        bankAccNo:user.bankAccNo,
        situtation:user.situtation,
        phone: user.phone,
        mobile: user.mobile,
        fax: user.fax,
        website: user.website,
        address: user.address,
        city: user.city,
        state: user.state,
        zip: user.zip,
        country: user.country
    }); 

    userAdd(user,function(err,user){  
                console.log(user)
               callback(err);
            });



  },

  function(err){
     if (!err)
        res.end();
     //TODO: Handle error

  }
);
function userAdd(user){
    //console.log(user)
    user.register(user, function(err, user) {
            async.parallel({

                leave:function(callback){
                    //add some leaves for user
                    _availLeaves(req.ID,user._id,function(err,leaves){
                          callback(err,leaves);  
                    });
                },
                salary:function(callback){
                    //add salary structure for employee
                    _salaryStructure(req.ID,user._id,function(err,structure){
                        callback(err,structure);
                    });
                }
            }, function(err, results) {       
                console.log(results)     
               if(!err){return results;}

                res.write(JSON.stringify({error: err,message:config.msg.SUCCESSFULLY_ADDED,user:'User create Successfully'}));

            });

    });
}

    }

    function _salaryStructure(loginId,userId,cb){
        var structure = new Structure({
            userId: userId,
            addedBy: loginId,
        });
        structure.save(function(err,structure){
            cb(err,structure);
        });        
    }
    function _availLeaves(loginId,userId,cb){
        var leave = new LeaveAvailable({
            "userId":userId,
            "bl" : 0.50,
            "fl" : 2,    
            "cl" : 1,  
            "pl" : (new Date().getDate()<=15)?0.75:0
        });

        leave.save(function(err,leaves){
            cb(err,'leavesAdded')
        }); 
    }
Community
  • 1
  • 1
skymon
  • 850
  • 1
  • 12
  • 19
  • I have tried this , I got following error at res.write : TypeError: First argument must be a string or Buffer at ServerResponse.OutgoingMessage.write (_http_outgoing.js:456:11) – GsMalhotra Feb 21 '17 at 12:18
  • Sorry, forgot about the stringification, updated the code with JSON.stringify() – skymon Feb 21 '17 at 12:29
  • Now, Data goes to Db, Please tell how I can send response to client side i.e res.send() – GsMalhotra Feb 21 '17 at 13:19
  • The updated code included the res.end in the callback function of async.each() - the lines "if (!err) res.end()". Did you update these in your code? – skymon Feb 21 '17 at 13:50
  • Yes , I have update this , but I didn't get response on client side – GsMalhotra Feb 24 '17 at 05:17
0

This is a complicated code - certainly not a minimal example to reproduce the problem - so let me give you a general explanation that you can use to track down and fix your problem.

async.parallel and async.each are very different.

With parallel you run a collection of functions in parallel. With each you apply a single iteratee function to every element in a collection, also in parallel.

In each of those cases you need to make sure that every function invokes its callback at some point (either with error or success) or otherwise the entire operation will not finish.

Now, after every operation has taken place, you need to invoke the res.send() method once.

E.g. if you had something like this:

async.each(collection, (element, cb) => {
    // you should not return response here
}, err => {
    // you should return response here
});

And that is true no matter what you have in the iteratee function above

See:

rsp
  • 107,747
  • 29
  • 201
  • 177