Search code examples
javascriptnode.jsloopbackjs

Strongloop Loopback - asynchronous functions handling in remote method (inside for each function)


I am developing a api using Loopback and I develop some remote method to retrieve data from efferent modules and rearrange the data as I wish. This is my sample code.

mainModule.viewAll = function(cb) {
    var mainFilter = {fields: ['f_name', 'l_name', 'id'], where: {status: 1}};
    var cEmp = null;
    mainModule.find(mainFilter, function(err, mainModules) {
      var returnArray = [];
      var returnEle;
      var secondModule = app.models.secondModule;

      mainModules.forEach(emp=>{
        returnEle = {};
        returnEle['name'] = emp.name;
          secondModule.count({ where: { type: 1 }}, function (err, count) {
              returnEle['field1'] = count;
              console.log(count);
          });
          secondModule.count({ where: { type: 1 } }, function (err, count) {
              returnEle['field2'] = count;
              console.log(count);
          });
          secondModule.count({ where: { type: 1 } }, function (err, count) {
              returnEle['field3'] = count;
              console.log(count);
          });
        returnArray.push(returnEle);

      });
      cb(null, returnArray);
    });
  };

  mainModule.remoteMethod('viewAll', {
    'http': {'verb': 'get', 'path': '/viewAll'},
    returns: {arg: 'profiles', type: 'Array'},
  });

And my response is like this,

{
  "profiles":[
    {
      "name":"Jhone",
      "id":1
    },
    {
      "name":"Shaam",
      "id":2
    },
    {
      "name":"Viki",
      "id":3
    }
    ] 
}

As you see here it only responce with the name and id fields no details about 'filed1', 'field2', 'field3'.But in console log 'field1','field2','field3' displaying perfectly.

I found that the reason could be the asynchronous behavior of the JavaScript. I study on some methods to fix this problem like using callback function, Promise etc. but none of those are fit with situation. (Promises seams little more efficient, so I tried to wrap the second module functions with the one promise and entire 'for each' function to another promise and cb(null, returnArray); was set to the then function. But it also didn't work).

I am new to the Loopback, So if someone know the answer please help me.


Solution

  • Use async.eachOf to apply async operation on each modules, then for each modules, use async.parallel to compute your 3 count in parallel :

    var returnArray = [];
    
    async.eachOf(mainModules, function(module, index, acb){
    
         // for each module do parallel count
    
        async.parallel({
    
            field1: function(pcb){
                secondModule.count({ where: { type: 1 }}, pcb);
            },
    
            field2: function(pcb){
                secondModule.count({ where: { type: 1 } }, pcb);
            },
    
            field3: function(pcb){
                secondModule.count({ where: { type: 1 } }, pcb);
            }
        }, function(err, result){
    
            // final parallel callback, when all parallel count are finished
            if(err || !result)
            {
                return acb(err || true);
            }
            else
            {
                result.name = module.name;
    
                // here result contains the 3 count in result["field1"], result["field2"] and result["field3"]
    
                returnArray.push(result);
    
                return acb(null);
            }
        })
    
    
        }, function(err){
           // final async.each of callback when all modules are proceed
           if(err)
           {
              // do stg
            }
           else
          {
              return cb(null, returnArray)
          }
      })