-1

-Reserved flights is an array in the scheme which has the flights a user reserved stored into it.

  • I am trying to return all the flights in an array to the front end. Like the following example:- //MUST BE Array of objects
[
  {
    _id: new ObjectId("61a4fa41fa24c144efce8038"),
    FlightNumber: '1',
    DepartureTime: 2013-08-03T02:00:00.000Z,
    To: 'Cairo',
    From: 'Alexandria',
    ArrivalTime: 2014-08-03T02:00:00.000Z,   
    First: 1,
    EconomySeats: 2,
    BusinessSeats: 3,
    ArrivalTerminal: ' ',
    DepartureTerminal: ' ',
    AvailableFSeats: [ 1 ],
    AvailableESeats: [ 1, 2 ],
    AvailableBSeats: [ 1, 2, 3 ],
    createdAt: 2021-11-28T22:26:27.339Z,     
    updatedAt: 2021-11-29T22:09:13.946Z,     
    __v: 0,
    BaggageAllowance: '6 kg',
    TicketPrice: 5555,
    Type: 'Normal'
  },
  {
    _id: new ObjectId("61a51f3dcf237cbdc514698a"),
    FlightNumber: '2',
    DepartureTime: 2013-08-03T02:00:00.000Z,
    To: 'Egypt',
    From: 'Saudi Arabia',
    ArrivalTime: 2014-08-03T02:00:00.000Z,   
    First: 4,
    EconomySeats: 3,
    BusinessSeats: 3,
    ArrivalTerminal: 'Jaddah Airport',       
    DepartureTerminal: 'Cairo Airport',      
    AvailableFSeats: [ 1, 2, 3, 4 ],
    AvailableESeats: [ 1, 2, 3 ],
    AvailableBSeats: [ 1, 2, 3 ],
    BaggageAllowance: '50 KG',
    Type: 'Normal',
    TicketPrice: 10000,
    createdAt: 2021-11-29T18:43:09.158Z,     
    updatedAt: 2021-11-29T22:08:35.212Z,     
    __v: 0
  }
]

-Here's the code that I've reached to:

UserRoutes.get('/Showresflights', (req,res) => {



      var rf = [];
    var flights = [];


  User.findById("61a52b332239b52f7ef5cc68", function (err, docs) {

  rf = docs.ReservedFlights;  
  for(var i=0;i<rf.length;i++)
  {

    Flight.findById(rf[i]).then(result => {
      //console.log(result);
      flights[i]=result;
    })
    .catch(err => {
      console.log(err);
    });
  }

  console.log("flights:" + flights);
  res.send(flights);


});

  });

  • console.log(result) returns the following:

//every flight being returned in object alone without being in array of objects which is needed.


{
  _id: new ObjectId("61a4fa41fa24c144efce8038"),
  FlightNumber: '1',
  DepartureTime: 2013-08-03T02:00:00.000Z,   
  To: 'Cairo',
  From: 'Alexandria',
  ArrivalTime: 2014-08-03T02:00:00.000Z,     
  First: 1,
  EconomySeats: 2,
  BusinessSeats: 3,
  ArrivalTerminal: ' ',
  DepartureTerminal: ' ',
  AvailableFSeats: [ 1 ],
  AvailableESeats: [ 1, 2 ],
  AvailableBSeats: [ 1, 2, 3 ],
  createdAt: 2021-11-28T22:26:27.339Z,       
  updatedAt: 2021-11-29T22:09:13.946Z,       
  __v: 0,
  BaggageAllowance: '6 kg',
  TicketPrice: 5555,
  Type: 'Normal'
}
{
  _id: new ObjectId("61a51f3dcf237cbdc514698a"),
  FlightNumber: '2',
  DepartureTime: 2013-08-03T02:00:00.000Z,   
  To: 'Egypt',
  From: 'Saudi Arabia',
  ArrivalTime: 2014-08-03T02:00:00.000Z,     
  First: 4,
  EconomySeats: 3,
  BusinessSeats: 3,
  ArrivalTerminal: 'Jaddah Airport',
  DepartureTerminal: 'Cairo Airport',        
  AvailableFSeats: [ 1, 2, 3, 4 ],
  AvailableESeats: [ 1, 2, 3 ],
  AvailableBSeats: [ 1, 2, 3 ],
  BaggageAllowance: '50 KG',
  Type: 'Normal',
  TicketPrice: 10000,
  createdAt: 2021-11-29T18:43:09.158Z,       
  updatedAt: 2021-11-29T22:08:35.212Z,       
  __v: 0
}

  • I tried to make the flights array as seen in the previous code to save the result of each flight inside of it in each iteration, but it looks like that nothing is saved due to the .then

-I thought about saving each object that are being returned from the result, but I don't know what is the exact syntax to do that as I dont even know what is the type of result.

xs0mE1
  • 77
  • 6
  • why not just push it to your array `flights` on successful findByID like `flights.push(result)`? And `if (i +1 == rf.length)` (your last iteration) send the res back to frontend.. – iLuvLogix Dec 01 '21 at 15:37
  • 1
    In the future, rather than posting a wall'o'code copied straight from your app please create a minimal reproduction example. This is covered in detail in the [help center](https://stackoverflow.com/help), specifically in [how to ask](https://stackoverflow.com/help/how-to-ask). – Jared Smith Dec 01 '21 at 15:49
  • @iLuvLogix because it's just a clumsy way of dealing with `.then()`? And `await` is _so_ much cleaner? :) – Jeremy Thille Dec 01 '21 at 15:57
  • @JeremyThille Fully agreed - therefore the upvote ;) – iLuvLogix Dec 01 '21 at 16:07
  • @iLuvLogix Haha thanks ^^ – Jeremy Thille Dec 01 '21 at 16:10

2 Answers2

2

Super classic question on "how to return the response from an asynchronous call?"

Mongoose methods are asynchronous, you can await them. Also add .lean() to return simple JSON (faster) and .exec() to return a true Promise you can await.

UserRoutes.get('/Showresflights', async (req, res) => {

  let flights = [];

  try {
    const rfs = (await User.findById("61a52b332239b52f7ef5cc68")).ReservedFlights;

    for (let rf of rfs) flights.push(await Flight.findById(rf).lean().exec());

    console.log("flights:" + flights);
    res.json(flights);
  } catch (err) {
    console.log(err);
    res.status(500).json(err); // Reply to your client in case of error, otherwise it's just gonna hang forever
  }
});

The problem with this though is, you are making one database call per flight. You can make one call for all the flights at once:

UserRoutes.get('/Showresflights', async (req, res) => {

  try {
    const rfs = (await User.findById("61a52b332239b52f7ef5cc68").lean().exec()).ReservedFlights;

    const flights = await Flight.find({
      _id: { $in: rfs }
    }).lean().exec();

    console.log("flights:" + flights);
    res.json(flights);
  } catch (err) {
    console.log(err);
    res.status(500).json(err);
  }
});

An even better solution would be to have your flights directly populated by Mongoose, in your schema. One single database call for the whole:

const user = await User.findById("61a52b332239b52f7ef5cc68")
    .populate("ReservedFlights")
    .select("ReservedFlights") // optional, but you just select the field you're interested in
    .lean()
    .exec();

res.json(user.ReservedFlights); // bam
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
0

The Code within your .then() block is executed asynchronious, So the for loop will be done, before all the Flight.findById(rf[i]) calls are finished.

You need to correctly await all the stuff.

Here's one example which executes everything in parallel and waits for the examples in the end using Array.map() and Promise.all():

UserRoutes.get('/Showresflights', (req, res) => {

    // added async keyword to callback function so we can use "await" within callback
    User.findById("61a52b332239b52f7ef5cc68", async function (err, docs) {

        // correctly handle error event!
        if(err) {
            console.error(err)
            res.status(500).send('Server error')
            return
        }

        // use try catch for error handling instead of .catch()
        try {

            // I call Array.from() since I am not sure if docs.ReservedFlights is a real array!.
            // you can probably omit the Array.from()..
            const rf = Array.from(docs.ReservedFlights).map(flightId => {
                // call the async function and return it's promise
                return Flight.findById(flightId)
            })

            // now await all the Promises since they are async operations.
            const flights = await Promise.all(rf)

            // after the for loop is done, send back result.
            console.log("flights:" + flights);
            res.status(200).send(flights);

        } catch (err) {

            // on any error, send back a response!
            console.log(err);
            res.status(500).send('Server error.')
        }

    });
});

Silvan Bregy
  • 2,544
  • 1
  • 8
  • 21
  • `Array.from(docs.ReservedFlights).map(flightId => { return Flight.findById(flightId) })` could be rewritten `docs.ReservedFlights.map(Flight.findById);` – Jeremy Thille Dec 01 '21 at 16:01
  • I commented it. I am not sure if it is a true array. ^^ There's the comment, which says it can probably be removed. – Silvan Bregy Dec 01 '21 at 16:02
  • The thing is, you can't omit it in your code, because you didn't use `.lean()`. So, Mongoose doesn't return a simple array. It returns a collection of Mongoose objects, with methods like `.save()` that we don't need here. So you can use `.lean()`, get simple and quick JSON, and omit `Array.from` because it's already an array! – Jeremy Thille Dec 01 '21 at 16:04
  • I don't know mongose. And I simply keep it like it is.. I upvoted your answer and that's it. – Silvan Bregy Dec 01 '21 at 16:05
  • Thanks man, I appreciate it – Jeremy Thille Dec 01 '21 at 16:12