0

I have the below sequence of the chained loop which I want to return using promises but I get the response before the forEach is executed in my code... Can anyone tell me where I am going wrong... I would like to do it using native Promises and would not prefer to use await/async so I get a better understanding of how Promises function.

Details.find(function(err,details){
    if(err){
        res.send(err)
      }else{
          console.log("----------First Promise------------")
          return details
      }
}).then(result1 => {
    result1.forEach(function(item){
        renderData = {}
        OrgChart.findOne({GID:item.gid},function(err,detail){
                console.log("Detail is ------> " + detail.DISPLAY_NAME)
                if(err){
                    res.send(err)
                }else{
                    return detail.DISPLAY_NAME
                }
            }).then( result2 => {
                renderData.gid = result2.DISPLAY_NAME
                renderData.pageouttime = item.pageouttime
                renderData.createdAt = item.createdAt
                renderData.oncall = item.oncall
                renderData.comments = item.comments
                renderData.actionLink = item._id.toString()              
                console.log(renderData)
                dataArr.push(renderData)

            })      
    })
}).then(result3 => {
    console.log("Final Result is ----> " + result3)
    response.data = result3
    res.json(response) 
}) 

Inside the forEach, I want to get a value using a value of the row. I am new to node js and Promises... I want to achieve something like below but using Promises.

Example sequence I want to Achieve through Promises

var someArray = []
var DetailsObj = Details.find()
DetailsObj.each(function(item){
   var newMap = {}
   newMap.prop1=item.prop1
   newMap.prop2 = item.prop2
   newMap.prop3 = OrgChart.find({id:item.prop3}).displayName
   someArray.push(newMap)
})

Please, can anyone let me know where I am going wrong?

Update 1(Not Working)

return Promise.all(result1.map(function(item){
        renderData = {}
        OrgChart.findOne({GID:item.gid},function(err,detail){
                console.log("Detail is ------> " + detail.DISPLAY_NAME)
                if(err){
                    res.send(err)
                }else{
                    return detail.DISPLAY_NAME
                }
            }).then(result2 => {
                renderData.gid = result2.DISPLAY_NAME
                renderData.pageouttime = item.pageouttime
                renderData.createdAt = item.createdAt
                renderData.oncall = item.oncall
                renderData.comments = item.comments
                renderData.actionLink = item._id.toString()              
                console.log(renderData)
                dataArr.push(renderData)
            })      
    }))

Still i get an empty array

Update 2 (Added return from the map callback--- Still not Working)

return Promise.all(result1.map(function(item){
        renderData = {}
        OrgChart.findOne({GID:item.gid},function(err,detail){
                console.log("Detail is ------> " + detail.DISPLAY_NAME)
                if(err){
                    res.send(err)
                }else{
                    return detail.DISPLAY_NAME
                }
            }).then(result2 => {
                renderData.gid = result2.DISPLAY_NAME
                renderData.pageouttime = item.pageouttime
                renderData.createdAt = item.createdAt
                renderData.oncall = item.oncall
                renderData.comments = item.comments
                renderData.actionLink = item._id.toString()              
                console.log(renderData)
                dataArr.push(renderData)
            }) 
        return dataArr             
    })
)

Update 3(Updated after returning from the then() callback in the Promise.all() block --- Still not Working)

  return Promise.all(result1.map(function(item){
        renderData = {}
        OrgChart.findOne({GID:item.gid},function(err,detail){
                console.log("Detail is ------> " + detail.DISPLAY_NAME)
                if(err){
                    res.send(err)
                }else{
                    return detail.DISPLAY_NAME
                }
            }).exec().then(result2 => {
                renderData.gid = result2.DISPLAY_NAME
                renderData.pageouttime = item.pageouttime
                renderData.createdAt = item.createdAt
                renderData.oncall = item.oncall
                renderData.comments = item.comments
                renderData.actionLink = item._id.toString()              

                return renderData
            })            
    })
)
9
  • you can try Promise.all(), insted of using foreach, insert your queries into an array, and process it through Promise.all() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jan 30, 2018 at 13:17
  • Tried but still no luck ... have put the updated code in that i tried Commented Jan 30, 2018 at 13:56
  • 1
    @Apoorv Your update misses to return the promise from the map callback Commented Jan 30, 2018 at 14:00
  • @Bergi .. Added the return statement from the map callback ... but still no luck ... have updated above .... i am still getting the below response {"status":200,"data":[[],[],[],[],[],[],[],[],[]],"message":null} Commented Jan 30, 2018 at 14:30
  • 1
    Also one tip; not working can only be answered by you're doing something wrong. not very helpful for anyone. if something is not working then you usually expect something but something else happens. You should provide this information. Like I expected .... but got error ... or got ... instead. Commented Jan 30, 2018 at 18:50

2 Answers 2

2

First of all, you should properly promisify your functions:

function findDetails() {
    return new Promise((resolve, reject) => {
        Details.find((err, details) => {
            if (err) reject(err);
            else resolve(details);
        });
    });
}
function findChart(gid) {
    return new Promise((resolve, reject) => {
        OrgChart.findOne({GID:item.gid}, (err, detail) => {
            if (err) reject(err);
            else resolve(detail);
        });
    });
}

or, as your library seems to support for simplicity (notice we're not passing any callbacks!):

function findDetails() {
    return Details.find().exec();
}
function findChart(gid) {
    return OrgChart.findOne({GID:item.gid}).exec();
}

Now we can build the promise chain from those (notice all the return statements!):

findDetails().then(details =>
    console.log("----------First Promise------------");
    return Promise.all(details.map(item => {
//  ^^^^^^
        return findChart(item.gid).then(detail => 
//      ^^^^^^
            console.log("Detail is ------> " + detail.DISPLAY_NAME)
            const renderData = {
                gid: detail.DISPLAY_NAME,
                pageouttime: item.pageouttime,
                createdAt: item.createdAt,
                oncall: item.oncall,
                comments: item.comments,
                actionLink: item._id.toString(),
            };
            console.log(renderData);
            return renderData;
//          ^^^^^^
        });
    }));
}).then(dataArr => {
    console.log("Final Result is ----> " + dataArr);
    response.data = dataArr;
    res.json(response);
}, err => {
    res.send(err);
});
Sign up to request clarification or add additional context in comments.

3 Comments

I'm not familiar with Sails and not sure if that is actually the api that OP is using but sails documentation say that promises are an alternative to exec so find and findOne should return a promise without the exec
@HMR Thanks, even simpler then. In any case the point I was trying to make is that no callbacks should be passed to find(One), only to then.
@Bergi Thanks for your solution ... it worked just the way i wanted it to ..... i finally got what you are trying to explain .... if i am not wrong but you mean to say that code block with findOne is not behaving as a promise at all ... and after the first block my code is returning a blank array... i really need to get my concepts of Promises in track .... Thanks all
0

If it is Sails you are using (should add the tag in the question and mention it) then according to the documentation it supports promises. But the documentation says that promises are an alternative to exec So your code should look like this:

Details.find()
.then(
  result =>
    Promise.all(
      result.map(
        item=>
          OrgChart.findOne({GID:item.gid})
          .then(//here is where your code is confusing
            // does detail have detail.DISPLAY_NAME.DISPLAY_NAME?
            // I assume it has not
            details=>({
              gid : details.DISPLAY_NAME,
              pageouttime : item.pageouttime,
              createdAt : item.createdAt,
              oncall : item.oncall,
              comments : item.comments,
              actionLink : item._id.toString()
            })
          )
      )
  )  
)
.then(
  results=>{
    console.log("results are:",results);
  }
)
.catch(
  err=>console.error("Something went wrong:",err)
);

5 Comments

No i am not using Sails... the part you are referring to is mongoose syntax ... and yes i should have atleast tagged mongooose
@Apoorv Ok, should be fine then, sales and mongoose are similar. Query is a promise: A Query has a .then() function, and thus can be used as a promise. but exec also returns a promise. As Bergi stated; you don't need to provide callback functions, only resolve and reject listeners.
In Mongoose queries are not promises but they have a .then() function for yield and async/await ... I am not sure what that means .... but if we want a full/fledge promise the documentation says to use exec() .....mongoosejs.com/docs/4.x/docs/promises.html
@Apoorv The 5.0.2 documentation literally says: A Query has a .then() function, and thus can be used as a promise. is the code provided in the answer giving you errors or unexpected results? I'd try running it in a single file first instead of part of a express like application so you can just run it from the command prompt and debug it (node --inspect-brk index.js open deftools in chrome and click on the node icon)
Yes i just saw that in 5.0.2... but i am currently using 4.13.0 .... i havent tried your solution ... .but will surely try it out .... Thanks again for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.