kathir
kathir

Reputation: 4285

Node js Nested Loops On Async and Await

My Question is How To Write Nested Loops In Node 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.

Upvotes: 1

Views: 1927

Answers (2)

kathir
kathir

Reputation: 4285

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

Upvotes: 1

HMR
HMR

Reputation: 39270

Since mongoose should return promises you don't need new Promise. You can use map to map data into promises and then use Promise.all to wait for them while they all simultaneously execute. 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],...]. 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.

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.

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:

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

Upvotes: 1

Related Questions