【问题标题】:Node js Nested Loops On Async and AwaitNode js在异步和等待上的嵌套循环
【发布时间】:2018-07-13 12:19:58
【问题描述】:

我的问题是如何在 Node Js 中编写嵌套循环

我的代码是

var result = db.data;
var FirstArray= new Array();
var SecondArray= new Array();
GetUserData();
async function GetUserData(){
    for (let info of result) {
         await getUserInfo(info);
    }
    res.send({status:"True", data: FirstArray, newdata:SecondArray  });
 }
    function getUserInfo(info){
        return new Promise(( resolve, reject )=>{
             UserModel.UserType.findOne({'_id': info.UserId }, usersProjection, function(err, UserData) {
                 if(err) {
                    res.send({status:"Fale", Error:err });
                    reject(err);
                 } else {
                        var data = UserData;
                        FirstArray.push(data);
                        GetUser();
                        async function GetUser(){
                           for (let newinfo of data ) {
                               await getnewUserInfo(newinfo);
                           }
                       }
                       function getnewUserInfo(newinfo){
                          return new Promise(( resolve, reject )=>{
                             UserModel.UserTypeNew.findOne({'_id': newinfo.UserId }, usersProjection, function(newerr, UserData) {
                               if(newerr) {
                                   res.send({status:"Fale", Error:newerr });
                                   reject(err);
                              } else {
                                  SecondArray.push(UserData)
                                 resolve();
                               }
                            });
                         });
                       }
                 }
             });
        });
     }

我将只获取第一个循环详细信息 如何获取第二个循环详细信息。

也建议另一种方法。

那么哪种方法是嵌套循环的最佳实践。

【问题讨论】:

  • 如果你有一个工作循环但想改进它,这个问题最好在Code Review Stack Exchange 上提出。
  • 我相信 OP 是在询问如何获取第二个循环的详细信息,但它并不完全清楚。如果是这样,那将是代码审查的主题。

标签: javascript arrays node.js mongoose async-await


【解决方案1】:
exports.GetPostList = function (req, res) {
var SkipCoun = 0;
SkipCoun = parseInt(req.params.Limit) * 10;
QuestionsPostModel.QuestionsPostType.find({}, {}, { sort: { createdAt: -1 }, skip: SkipCoun, limit: 10 }, function (err, result) {
    if (err) {
        res.status(500).send({ status: "False", message: "Some error occurred while Find Following Users ." });
    } else {
        const GetUserData = (result) =>
            Promise.all(
                result.map(info => getPostInfo(info))
            ).then( result =>{ console.log(result);  res.send({ status: "True", data: result }) }
            ).catch(err => res.send({ status: "False", Error: err }));


        const getPostInfo = info =>
            Promise.all([
                UserModel.UserType.findOne({ '_id': info.UserId }, usersProjection).exec(),
                FollowModel.FollowUserType.count({ 'UserId': info.UserId }).exec(),
                RatingModel.QuestionsRating.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
                RatingModel.QuestionsRating.count({ 'UserId': req.params.UserId, 'PostId': info._id, 'PostUserId': info.UserId, 'ActiveStates': 'Active' }).exec(),
                AnswerModel.QuestionsAnwer.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
                AnswerModel.QuestionsAnwer.find({ 'PostId': info._id }, 'AnswerText UserId Date').exec()
            ]).then(data => {
                let UserData = data[0];
                let followCount = data[1];
                let ratingCount = data[2];
                let UserRating = data[3];
                let AnswerCount = data[4];
                let Answerdata = data[5];


                var AnswersArray= new Array();

               return GetAnsUserData();
                async function GetAnsUserData(){
                    for (let ansInfo of Answerdata) {
                        await getAnswerInfo(ansInfo);
                     }

                     let result = {
                        _id: info._id,
                        UserId: UserData._id,
                        UserName: UserData.UserName,
                        UserCategoryId: UserData.UserCategoryId,
                        UserCategoryName: UserData.UserCategoryName,
                        UserImage: UserData.UserImage,
                        UserCompany: UserData.UserCompany,
                        UserProfession: UserData.UserProfession,
                        Followers:followCount,
                        PostTopicId: info.PostTopicId,
                        PostTopicName: info.PostTopicName,
                        PostDate: info.PostDate,
                        PostText: info.PostText ,
                        PostLink: info.PostLink,
                        PostImage: info.PostImage,
                        PostVideo: info.PostVideo,
                        RatingCount: ratingCount,
                        UserRating: UserRating,
                        AnswersCount: AnswerCount,
                        Answers: AnswersArray,

                    };
                    return result;
                  }

                  function getAnswerInfo(ansInfo){
                    return new Promise(( resolve, reject )=>{
                        UserModel.UserType.findOne({'_id': ansInfo.UserId }, usersProjection, function(err, AnsUserData) {
                            if(err) {
                                res.send({status:"Fale", Error:err });
                                reject(err);
                            } else {
                                FollowModel.FollowUserType.count({'UserId': AnsUserData._id}, function(newerr, count) {
                                    if(newerr){
                                        res.send({status:"Fale", Error:newerr });
                                        reject(newerr);
                                    }else{
                                        var newArray = [];
                                        newArray.push( {
                                                        _id: ansInfo._id,
                                                        UserId: AnsUserData._id,
                                                        UserName: AnsUserData.UserName,
                                                        UserCategoryId: AnsUserData.UserCategoryId,
                                                        UserCategoryName: AnsUserData.UserCategoryName,
                                                        UserImage: AnsUserData.UserImage,
                                                        UserCompany: AnsUserData.UserCompany,
                                                        UserProfession: AnsUserData.UserProfession,
                                                        Followers: count,
                                                        Date: ansInfo.Date,
                                                        PostId: ansInfo.PostId,
                                                        PostUserId: ansInfo.PostUserId ,
                                                        AnswerText: ansInfo.AnswerText
                                                    }
                                        );
                                        AnswersArray.push(newArray[0]);
                                        resolve(newArray[0]);
                                    }
                                });
                            }
                        });
                    });
                }


            }).catch(error => {
                console.log(error)
            })

         GetUserData(result);

    }
});
};

终于找到解决办法了

感谢大家

【讨论】:

    【解决方案2】:

    由于 mongoose 应该返回 Promise,因此您不需要新的 Promise。您可以使用 map 将数据映射到 Promise 中,然后使用 Promise.all 等待它们同时执行。您当前的代码一个一个地执行查询(只有在当前完成时才执行下一个)。这不是必需的,而且非常慢。

    因此您可以将db.data 映射到[[first,second],[first,second],...]。我不映射 findOne 的结果,因为它不应该返回一个数组,并且奇怪的是 something of resultOfFindOne 确实有效,因为 findOne 应该返回一个文档或 null。

    UserModel.UserType.findOneUserModel.UserTypeNew.findOne 都尝试通过_id 查找一条记录,并且都使用相同的_id,因此无需执行 UserType 查询,然后当返回执行 UserTypeNew 查询时,您只需对这两个查询都使用info.UserId

    const GetUserData = (result) => 
      Promise.all(
        result.map(info=>getUserInfo(info))
      ).then(
        results=>{//results should be [[first,second],[first,second],...]
          let [FirstArray,SecondArray] = results.reduce(
            ([allFirst,allSecond],[first,second])=>
              [allFirst.concat([first]),allSecond.concat([second])],
            [[],[]]
          );
          res.send({ status: "True", data: FirstArray, newdata: SecondArray })
        }
      ).catch(
        err=>
          res.send({status:"Fale", Error:err })
      );
    const getUserInfo = info =>
      //mongoose can return promises, no need to convert callback api to promise:
      //http://mongoosejs.com/docs/queries.html
      Promise.all([
        UserModel.UserType.findOne({ '_id': info.UserId }, usersProjection).exec(),
        UserModel.UserTypeNew.findOne({ '_id': info.UserId }, usersProjection).exec()
      ]);
    //when using const the function is not hoisted so you can't call a function
    //  before it was declared.
    GetUserData(db.data);
    

    如果您使用的是旧版本的 mongoose(不是 5.xxx),您可能仍需要将基于回调的 api 转换为 Promise,它看起来有点像这样:

    const asPromise = object => fn => args =>
      new Promise(
        (resolve,reject)=>
          fn.apply(
            object,
            args.concat([
              (...result)=>
                (result[0])//first argument of callback is error
                  ? reject(result[0])//reject with error
                  : resolve(result.slice(1,result.length))//resolve with result(s)
            ])
          )
      );
    
    const newUserType = asPromise(UserModel.UserTypeNew);
    const userType = asPromise(UserModel.UserType);
    
    //making a query with callback but convert it to promise
    newUserType(UserModel.UserTypeNew.findOne)([
      { '_id': info.UserId }, usersProjection
    ]).then(//this will resolve as array, only need first item
      ([result])=>result
    );    
    
    userType(UserModel.UserType.findOne)([//note that I'm not passing UserModel.UserTypeNew.findOne
      { '_id': info.UserId }, usersProjection
    ]).then(//this will resolve as array, only need first item
      ([result])=>result
    );
    

    【讨论】:

    • 感谢您的回答。我会尝试第一种方法,但我没有得到我的确切结果!在您的第一种方法中:** secoundArray 如何再次循环并获得新的结果** 我的新问题是 [stackoverflow.com/questions/48597193/…]
    猜你喜欢
    • 1970-01-01
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2018-06-04
    • 2019-06-30
    • 2016-07-25
    • 2017-12-12
    相关资源
    最近更新 更多