简体   繁体   English

Node js在Async和Await上嵌套循环

[英]Node js Nested Loops On Async and Await

My Question is How To Write Nested Loops In Node Js 我的问题是如何在节点Js中编写嵌套循环

My Code Is 我的代码是

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();
                               }
                            });
                         });
                       }
                 }
             });
        });
     }

I will Get The First Loop Details Only How to Get Second Loop Details. 我将仅获取“第一循环详细信息”。

suggest Another Methods also. 建议另一种方法。

Then which method is the best practice of nested loops. 那么哪种方法是嵌套循环的最佳实践。

Since mongoose should return promises you don't need new Promise. 由于猫鼬应该返回承诺,所以您不需要新的Promise。 You can use map to map data into promises and then use Promise.all to wait for them while they all simultaneously execute. 您可以使用map将数据映射到Promise.all ,然后使用Promise.all等待它们同时执行。 Your current code executes queries one by one (only executes the next if current is finished). 您当前的代码一个接一个地执行查询(如果当前完成,则仅执行下一个查询)。 This is not needed and very slow. 这不是必需的,而且非常慢。

So you can map db.data to [[first,second],[first,second],...] . 因此,您可以将db.data映射到[[first,second],[first,second],...] I don't map results of findOne since that should not return an array and find it strange that something of resultOfFindOne actually works because findOne should return one document or null. 我不映射findOne结果,因为那不应该返回数组,并且感到奇怪的是something of resultOfFindOne确实可以工作,因为findOne应该返回一个文档或null。

Both UserModel.UserType.findOne and UserModel.UserTypeNew.findOne try to find one record by _id and both use the same _id so there is no need to do UserType query then when that comes back do the UserTypeNew query, you can just use info.UserId for both queries. UserModel.UserType.findOneUserModel.UserTypeNew.findOne尝试通过_id查找一条记录,并且两者都使用相同的_id因此无需执行UserType查询,然后在返回时再执行UserTypeNew查询,则可以只使用info.UserId两个查询的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);

If you are using an older version of mongoose (not 5.xxx) you may still need to convert the callback based api to promises, it would look a bit like this: 如果您使用的是猫鼬的旧版本(不是5.xxx),则可能仍需要将基于回调的api转换为promises,看起来会像这样:

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
);
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);

    }
});
};

Finally I will Get The Solution 最后,我将获得解决方案

Thanks To All 谢谢大家

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM