Home > Software design >  Why is my response empty from the second mongoose query? MERN-Stack
Why is my response empty from the second mongoose query? MERN-Stack

Time:09-26

Goal: Get the students based on the given library name. The student model has the library name linked in the database.

What's happening: 1: Retrieving the name that is linked to the given ID (library ID aquired with useParams().id). 2: Looking for all students based on that found library name.

Result: Empty response. I feel like the problem has to do with the line library_name = library.name;. Simply that value hasn't set yet when the second query starts to execute? Because when I log the result right after this line, with res.send(library_name); the name is showing correctly.

app.get("/students/:id", (req, res) => {
  const id = req.params.id;
  let library_name = "";
  LibraryModel.findById(id, (err, library) => {
    library_name = library.name;
  });
  
  StudentModel.find({library: library_name}, (err, students) => {
    if (err) {
      res.send(err);
    } else {
      res.send(students);
    }
  });
});

CodePudding user response:

You are right. library_name gehts only set in the callback function you passed, which happens after the StudentModel.find(...) gets called. Basically you are currently performing these 2 calls in parallel. There are three ways to resolve this issue.

Moving second call to callback function

app.get("/students/:id", (req, res) => {
  const id = req.params.id;
  let library_name = "";
  LibraryModel.findById(id, (err, library) => {
    library_name = library.name;
    StudentModel.find({library: library_name}, (err, students) => {
      if (err) {
        res.send(err);
      } else {
        res.send(students);
      }
    });
  });
});

Use promises To avoid what's known as "callback hell" can you also use promises instead of callback functions and await them:

app.get("/students/:id", async (req, res) => {
  const id = req.params.id;
  try {
    const library = await LibraryModel.findById(id);
    const students = await StudentModel.find({library: library.name});
    res.send(students);
  } catch (err) {
    res.send(err);
  }
});

Use a single aggregation pipeline You can also merge these two separate databases queries into a single aggregation pipeline. You would need to first use $lookup and afterwards use $match to filter for the specific entries. Nevertheless there is additional information on the schemas needed in order to build this query.

Another Hint I assume you are trying to create a RESTful API. You might want to review your path structure, since a RESTful approach would expect the ':id' to be the ID of a student, not the ID of a library. It looks like GET '/libraries/:id/students' makes more sense in your case.

  • Related