0

I have been trying to create a JSON object with the data that I pull from MongoDB database.

Last line res.status(200).json(userData) seems to return a response before the data processing is over, so I get an empty object without processed data as a response. Any ideas on how to solve this problem?

             // chats are defined before, but excluded here to make a code easier to read
             let userData = {};
             chats.forEach(function(chat){
               let chatId = chat.id;
               let userIds = chat['userIds'];
               UserAccountingData.find({userId: {$in : userIds}}, function(err, userAccountingData){
                  if(err){
                    console.log(err);
                    res.status(404).json('User data not found.');
                    return;
                  } else {
                  userAccountingData.forEach(function(data){
                    console.log({
                      imageUrl: data.imageUrl,
                      firstName: data.firstName,
                      lastName: data.lastName
                    });
                    userData[data.userId] = {
                      imageUrl: data.imageUrl,
                      firstName: data.firstName,
                      lastName: data.lastName
                    };
                  });
                }
               });
             });
             res.status(200).json(userData);

Console.log shows that there is a data coming from the database:

{ imageUrl: 'www.test.de', firstName: 'Fender', lastName: 'Fen' }
{ imageUrl: 'www.test.de', firstName: 'Baveler', lastName: 'Bav' }

Thank you for your time

Michalis Garganourakis
  • 2,872
  • 1
  • 11
  • 24
makeze
  • 55
  • 1
  • 1
  • 10
  • Can you confirm what is coming in data.userId? – Nikhil Goyal Jan 12 '20 at 14:35
  • It is just a chat object id in form of a string looking like this: "5b1232142512c6166c04e655" – makeze Jan 12 '20 at 14:39
  • As your `UserAccountingData.find` seems to be an asynchronous call. It won't get filled by the time you are returning the response. Try to fill the `userData` object and return the data as a promise. – Nikhil Goyal Jan 12 '20 at 14:42

1 Answers1

1

This is because the UserAccountingData.find runs asynchronously. So we need to add async/await logic to this code.

First, define the find function.

const findUserAccountingData = (userIds) => new Promise((resolve, reject) => {
    UserAccountingData.find({ userId: { $in: userIds } }, function (err, userAccountingData) {
        if (err) {
            return reject(err);
        }

        resolve(userAccountingData)
    })
});

Next, modify the original code like below.

let userData = {};
try {
    for (let chat of chats) {
        let chatId = chat.id;
        let userIds = chat['userIds'];
        const userAccountingData = await findUserAccountingData(userIds)
        userAccountingData.forEach(function (data) {
            console.log({
                imageUrl: data.imageUrl,
                firstName: data.firstName,
                lastName: data.lastName
            });
            userData[data.userId] = {
                imageUrl: data.imageUrl,
                firstName: data.firstName,
                lastName: data.lastName
            };
        });
    }
} catch (error) {
    console.log(error);
    // res.status(404).json('User data not found.');   // error doesn't occur when user data not exists.
    res.status(500).json(JSON.stringify(error));
}
res.status(200).json(userData);

Finally you need to mark the calling function as async.

TopW3
  • 1,477
  • 1
  • 8
  • 14
  • 1
    The current code runs serially. We can modify this code for improving performance. That is, we can write the code working exactly like Promise.all() – TopW3 Jan 12 '20 at 14:57
  • It works like supposed now. I did not know this technique. Thank you for the extra comments, I will do reading on this topic. – makeze Jan 12 '20 at 15:10