AlexDev
AlexDev

Reputation: 35

MongoDB find returns documents half the time

I'm using MongoDB with Express and I have a fetch to get a list of users and sort them by the amount of wins they achieved. The problem is that 80% of the time the same code returns a sorted list with no problem, but 20% of the time the response is an empty array [].

I have promises everywhere and I have crosschecked that the problem is in mongoDB's find method, not in the sort method. I know about concurrency and stuff, I just don't understand why this does not work.

app.get("/api/account/getSortedRank", (req, res) => {

    const { query } = req;
    const { userId } = query;

    var getFriends = [];

    User.findOne(
      {
        _id: userId
      },
      (err, user) => {
        if (err) {
          console.log("Server error");
        }
        user.friends.forEach(userFound => {
          getFriends.push(userFound.user);
        });

        // getFriends is always correct!

      }
    ).then(() => {
      User.find({
        _id: { $in: getFriends }
      })
        .sort({ wins: -1 })
        .then(sortedUsers => {

          // 50% of the time sortedUsers is an empty array!
          let usersList = [];
          sortedUsers.forEach(user => {
            usersList.push({
              firstName: user.firstName,
              lastName: user.lastName,
              userID: user._id,
              wins: user.wins
            });
          });
          return res.send({
            success: true,
            usersList
          });
        });
    });
  });


Upvotes: 1

Views: 118

Answers (1)

JohnnyHK
JohnnyHK

Reputation: 311925

You're mixing callbacks and promises here, which is likely ending up executing the findOne query twice, with different completion times. So getFriends is sometimes populated in time, but other times it isn't.

Instead, move the find query inside the findOne callback:

User.findOne(
  {
    _id: userId
  },
  (err, user) => {
    if (err) {
      console.log("Server error");
    }
    var getFriends = [];
    user.friends.forEach(userFound => {
      getFriends.push(userFound.user);
    });

    // getFriends is always correct!
    User.find({
      _id: { $in: getFriends }
    })
      .sort({ wins: -1 })
      .then(sortedUsers => {

        let usersList = [];
        sortedUsers.forEach(user => {
          usersList.push({
            firstName: user.firstName,
            lastName: user.lastName,
            userID: user._id,
            wins: user.wins
          });
        });
        return res.send({
          success: true,
          usersList
        });
      });
  }
);

Upvotes: 1

Related Questions