imin
imin

Reputation: 4578

nested query inside mongoose

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?

Upvotes: 0

Views: 189

Answers (2)

Akrion
Akrion

Reputation: 18525

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

Upvotes: 1

Qiaosen Huang
Qiaosen Huang

Reputation: 1133

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});
      });
  }
});

Upvotes: 1

Related Questions