0

I'm setting an array before a for loop, inside the for loop I use .push() to add data to the array but after this loop the array is empty.

MessageNotification.find({for: req.user.id}, (err, notifications) => {
    var userdata = [];
    notifications.forEach((notif) => {
        User.findById(notif.from, (err, user) => {
            userdata.push({
                id: user._id,
                username: user.username,
                thumbnail: user.thumbnail
            });
        });
    });
    console.log(userdata);
});

As you can see on the code I am running a mongoose query to find all notifications for a specific id, then, I am setting an array to get details about the sender of each notification. Inside a forEach loop I save the results in the array. Console.log on line 12 returns an empty array [] even though User.findById on line 4 gets the User data

  • Isn't `findById` asynchronous? – VLAZ Aug 26 '19 at 13:13
  • I think it *is* async, in which case your `forEach` will not populate `userdata` as it executes but each lookup will be done *later*. So at the time you run a `console.log` the information is not back yet. – VLAZ Aug 26 '19 at 13:15
  • 1
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – VLAZ Aug 26 '19 at 13:15
  • it is async. you need to make it sync or use promise etc. – user1984 Aug 26 '19 at 13:18
  • Yes, but mongoose doesn't support sync queries, how should I do that ? – AppInventor Account Aug 26 '19 at 13:35

2 Answers2

0

The problem here is actually that you're calling .forEach with an async calls inside. Rather than iterating over each item in the array, and running a separate query for each, you should use the $in operator which will check if any values match items within the array, with a single query.

silencedogood
  • 3,209
  • 1
  • 11
  • 36
0

The problem is you are doing and asynchronous call in forEach. You should either use async/await with for..of or promises in such cases.

In your case, actually there is no need to do multiple calls on User model, you can get the desired result in a single query. Try the below code:

MessageNotification.find({
    for: req.user.id
}, (err, notifications) => {
    const fromArr = notifications.map(({
        from
    }) => from);      // taking out **from** values from all notifications
    User.find({
        _id: {
            $in: fromArr
        }
    }, (err, users) => {        // single query to get the data
        const userData = users.map(({
            _id: id,
            username,
            thumbnail
        }) => {
           return {
              id,
              username,
              thumbnail
           };
        });
        console.log(userData);
    });
});
Mohammed Amir Ansari
  • 2,311
  • 2
  • 12
  • 26