0

I have a Student.find query which is run inside Room.find query as below:

Room.find({ schoolID:  mongoose.mongo.ObjectId(user.schoolID) }).sort({'level':'ascending','name':'ascending'}).then(function (roomList) {
  if (!roomList){
    console.log("no class room found")
  }else{
    console.log("class room found: " + roomList.length)
    var studentList = []
    for (var i = 0; i < roomList.length; i++){
      console.log(i)
      console.log("class room id: " + roomList[i]._id)
      console.log("class room name: " + roomList[i].name)
      Students.find({ schoolID:  mongoose.mongo.ObjectId(user.schoolID), classRoomID:  mongoose.mongo.ObjectId(roomList[i]._id) }).sort({'firstName':'ascending'}).then(function (data) {
        if (!data){
          console.log("no data found")
          return res.status(200).send({success: true, msg: 'No data found.'});
        }else{
          console.log("214 ada data: " + data.length)
          studentList[i] = data
          console.log("studentList " + i)
          console.log(studentList[i])
        }
      });
    }
    res.json({success: true, token: 'JWT ' + token, id: user._id, user: user, classRoom: roomList, students: studentList});    
  }
});

In the db, there are 6 class room and a different number of students for each class. In the console.log, I was expecting to see something like:

class room id: 01
class room name: my first class
studentList 0:
list of students from first class

class room id: 02
class room name: my second class
studentList 1:
list of students from 2nd class

class room id: 03
class room name: my third class
studentList 2:
list of students from 3rd class

because I assume the Students.find will be executed right after I output the console.log("class room name: + roomList[i].name)

But it turns out all the console.log("class room id") and console.log("class room name") are printed out first, then only it seems Students.find are executed, because my output is something like this:

class room id: 01
class room name: my first class
class room id: 02
class room name: my second class
class room id: 03
class room name: my third class
class room id: 04
class room name: my fourth class
class room id: 05
class room name: my fifth class
class room id: 06
class room name: my six class

list of students
list of students
list of students
list of students
list of students
list of students

If this is the case, how do I do a proper nested query?

imin
  • 4,504
  • 13
  • 56
  • 103

2 Answers2

1

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function.

Try:

Room.find({
  schoolID: mongoose.mongo.ObjectId(user.schoolID)
}).sort({
  'level': 'ascending',
  'name': 'ascending'
}).exec().then(function(roomList) {
  if (!roomList) {
    console.log("no class room found")
  } else {
    console.log("class room found: " + roomList.length)
    var studentList = []
    for (var i = 0; i < roomList.length; i++) {
      console.log(i)
      console.log("class room id: " + roomList[i]._id)
      console.log("class room name: " + roomList[i].name)
      Students.find({
        schoolID: mongoose.mongo.ObjectId(user.schoolID),
        classRoomID: mongoose.mongo.ObjectId(roomList[i]._id)
      }).sort({
        'firstName': 'ascending'
      }).exec().then(function(data) {
        if (!data) {
          console.log("no data found")
          return res.status(200).send({
            success: true,
            msg: 'No data found.'
          });
        } else {
          console.log("214 ada data: " + data.length)
          studentList[i] = data
          console.log("studentList " + i)
          console.log(studentList[i])
        }
      });
    }
    res.json({
      success: true,
      token: 'JWT ' + token,
      id: user._id,
      user: user,
      classRoom: roomList,
      students: studentList
    });
  }
});

The other issue you have is that you are trying to do for loop with async. It does not work that way ... (for loop would not wait and will keep going) either use Promise.All or a something among these lines

Akrion
  • 18,117
  • 1
  • 34
  • 54
  • Thanks, but `console.log("studentList " + i)` will always show `studentList 6`. The line `console.log(i)` directly below `for (var i = 0; i < roomList.length; i++)` will display `0` until `5` correctly (since there's 6 classes) , but it seems `i` under Students.find() will only be 6. My assumption is that because Students.find() will always be executed/finish executing only after the for loop finish... should it behave this way? – imin Nov 02 '18 at 17:06
  • What I need is for each Students.find() to complete executing after retrieving the roomList id and name, so that I can pass the result of Students.find() to each roomList[i].students (something like that) – imin Nov 02 '18 at 17:10
  • 1
    You can't use for loop with async. I updated the answer with a link for your reference. – Akrion Nov 02 '18 at 17:17
  • Thanks! I'll go with promise all. Your answer helped me to understand the problem and solution more, but I just realized that Qiaosen Huang has already given an answer on how to use Promise.all. +2 for your help! – imin Nov 02 '18 at 18:11
1
Room.find({ schoolID:  mongoose.mongo.ObjectId(user.schoolID) }).sort({'level':'ascending','name':'ascending'}).then(function (roomList) {
  if (!roomList){
    console.log("no class room found")
  }else{
    console.log("class room found: " + roomList.length)
    var promsies = [];
    if (roomList.length) return res.status(200).send({success: true, msg: 'No data found.'});
    for (var i = 0; i < roomList.length; i++){
      console.log(i)
      console.log("class room id: " + roomList[i]._id)
      console.log("class room name: " + roomList[i].name)
      promsies.push(Students.find({ schoolID:  mongoose.mongo.ObjectId(user.schoolID), classRoomID:  mongoose.mongo.ObjectId(roomList[i]._id) }).sort({'firstName':'ascending'}));
    }
    Promise.all(promsies).then(function (studentList) {
        res.json({success: true, token: 'JWT ' + token, id: user._id, user: user, classRoom: roomList, students: studentList});
      });
  }
});
Qiaosen Huang
  • 1,093
  • 1
  • 10
  • 25