将 q.all 正确放置在 array.map 和 _.forEach 中

Proper placement of q.all inside array.map with _.forEach

我有以下代码,它使用 find() 使用 array.map 提取的值搜索我的 mongodb。表示搜索returns一个对象,然后我用_.forEach来提取值。

我使用 this article 作为基础,但是他的示例和我的示例之间的区别在于他只使用了一个循环。我正在使用两个。在这种情况下,我应该把我的 q.all()?

放在哪里?

这是我的代码。 请注意是服务器端:

'use strict';
var q = require('q');

exports.downloadEmployee = function (req, res) {
    var tempCtr = [];

    if (req.params.hasdr === "yes") {
        return queries.generateDirectReportsCSV(req.params.id).then(function (directReports) {
            return directReports;
        }).then(function (directReports) {
            var empIDcoll = _.pluck(directReports.Data, "employeenumber");
            return empIDcoll;
        }).then(function (empIDcoll) {
            var promises = [];

            empIDcoll.map(function (id) {

                return EmployeeInfo.find({ employeeID: id }, function (err, results) {
                    if (err) { return err; }

                    _.forEach(results, function (item) {
                        if (item) {
                            tempCtr.push({
                                employeeID: item.employeeID,
                                employeeName: item.employeeName
                            });
                            promises.push(tempCtr);
                        }
                    });
                });

                q.all(promises).then(function (results) {
                    return res.json(results);
                });
            });
        });
    }

当我 运行 这样做时,我没有得到任何结果。

任何答案将不胜感激。

谢谢。

更新: 我决定修改我的代码并将 array.map 替换为通常的 for loop:

.then(function (empIDcoll) {

    for (var i = 0; i <= empIDcoll.length - 1; i++) {
        var promise = EmployeeInfo.find({ employeeID: empIDcoll[i] }, function (err, results) {
            if (err) { return err; }

            _.forEach(results, function (item) {
                if (item) {
                    tempCtr.push({
                        employeeID: item.employeeID,
                        employeeName: item.employeeName,
                        currentShift: item.currentShift,
                        isOpenToIntlAssignment: item.isOpenToIntlAssignment,
                        desiredRole1: item.desiredRole1,
                        desiredRole2: item.desiredRole2,
                        desiredRole3: item.desiredRole3,
                        desiredRoleOther: item.desiredRoleOther,
                        passportInfo: item.passportInfo,
                        visaInfo: item.visaInfo,
                        yrsInIT: item.yrsInIT,
                        yrsAsCustomerPM: item.yrsAsCustomerPM,
                        yrsAsCustomerProgM: item.yrsAsCustomerProgM,
                        primaryDomain: item.primaryDomain,
                        primaryDomainOther: item.primaryDomainOther,
                        primaryIndustry: item.primaryIndustry,
                        primaryIndustryOther: item.primaryIndustryOther,
                        isPMPCertified: item.isPMPCertified,
                        pmpCertExpiryDate: item.pmpCertExpiryDate,
                        isPGMPCertified: item.isPGMPCertified,
                        pgmpCertExpiryDate: item.pgmpCertExpiryDate,
                        isScrumCertified: item.isScrumCertified,
                        scrumCertExpiryDate: item.scrumCertExpiryDate,
                        biggestProjectTCV: item.biggestProjectTCV,
                        biggestTeamSizeManaged: item.biggestTeamSizeManaged,
                        avgTeamSizeManaged: item.avgTeamSizeManaged,
                        biggestBilledFTE: item.biggestBilledFTE,
                        avgBilledFTE: item.avgBilledFTE
                    });
                }
            });
        });
        promises.push(promise);
    }

    return q.all(promises).then(function(data){
        return res.json(data);
    });

});

...但它仍然没有返回任何内容。我做错了什么?

删除EmployeeInfo.find之前的return语句?

看看,

var promises = questions.map(function(question) {

        return $http({
            url   : 'upload/question',
            method: 'POST',
            data  : question
        });

    });

    return $q.all(promises);

第一次几乎正确!

当你这样做的时候:

var promises = [];
empIDcoll.map(function (id) {
    return EmployeeInfo.find({ employeeID: id }, function (err, results) {
        if (err) { return err; }
        _.forEach(results, function (item) {
            if (item) {
                tempCtr.push({
                    employeeID: item.employeeID,
                    employeeName: item.employeeName
                });
                promises.push(tempCtr);
            }
        });
    });

    q.all(promises).then(function (results) {
        return res.json(results);
    });
});

您的 q.all 位置错误(在 .map 内);并且您将 objects 推入 promises 数组,而不是实际的 promises。尝试做类似的事情:

// Here, we will build an array of promises by transforming each element of `empIDcoll` to a promise (via `.map`).
var promises = empIDcoll.map(function (id) {
    return EmployeeInfo.find({ employeeID: id }).exec(); // I assume that .exec() will return a promise.
});

q.all(promises).then(function (results) { // `results` will be an array, each element will contain the result of each promise pushed to `promises`.
    return res.json(results);
});

试试这个。这可能需要一些调整(让我们知道),因为我真的不知道您的应用程序/模型的结构。

我的第一个建议是首先停止循环访问 employeeId。 你可以像这样使用 mongoDB 的 $in 运算符

EmployeeInfo.find({ employeeID: {$in: empIDcoll} }, function (err, results) {
     if(err) {
       //handle error
       return err;
     }

     res.json(results);
});

但由于我不了解您的应用程序,所以我真的无法判断您是否想要循环访问 empIdColl。


遍历 empIdColl

现在我不确定您的 monogdb 查询是否会return 承诺,所以为了安全起见,我假设它不会

var promises = empIDcoll.map(function (id) {
    var singleDefer = q.defer(); //create a deferred object which has promise in it

    EmployeeInfo.find({ employeeID: id }, function(err, results) {
         if(err) {
             return singleDefer.reject(err);
         }

         return singleDefer.resolve(results); //resolve whole array
    });

    return singleDefer.promise;
});

q.all(promises)
.then(function (arrayOfResults) {
    var responseData = [];

    arrayOfResuls.forEach(function(results) {
          results.forEach(function(individualResult) {
              if(individualResult) {
                   responseData.push({
                       employeeID: item.employeeID,
                       ...
                       ...
                       avgBilledFTE: item.avgBilledFTE
                   });
              }
          });
    });

    return res.json(responseData);
})
.catch(function(err) {
    //handle error
});

我在这里发布我的工作解决方案,以供将来可能遇到相同问题的人使用。感谢 SinDeus 提供简单明了的解决方案。 :)

.then(function (empIDcoll) {

        // push user's employee number in first row
        empIDcoll.unshift(req.params.id);

        // return resolved promises from EmployeeInfo.find()
        // this will return user's direct reports' information (if any)
        var promises = empIDcoll.map(function (id) {
            return EmployeeInfo.find({ employeeID: id }).exec();
        });

        // Take resolved promises from above statement and iterate to get final results.
        q.all(promises).then(function (results) {
            _.forEach(results, function (item) {
                var len = item.length - 1;
                if (len >= 0) {
                    tempCtr.push({
                        employeeID: item[0].employeeID,
                        employeeName: item[0].employeeName
                        // ... other fields here ...
                    });
                }
            });
            return res.json(tempCtr);
        });
    });
}