-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.
CodePudding user response:
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
CodePudding user response:
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.')
}
});
});