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?

2 Answers 2

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});
      });
  }
});
Sign up to request clarification or add additional context in comments.

Comments

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

4 Comments

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?
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)
You can't use for loop with async. I updated the answer with a link for your reference.
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!

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.