sseggio
sseggio

Reputation: 75

NodeJs & Firebase nested forEach async await

I've started learning NodeJS to use it with Firebase in order to create Functions.

I'm currently stuck because I have nested forEach which must be async.

I'll try to be as understandable as possible.

I have 3 nodes:

I have to create a function to get all the terminals with their bookings associated.

So I have to get all the terminals, for each terminal I can get all the terminalbookings associated (the node key is the terminal id and all the values are bookings id). enter image description here

And then when I have all the terminalbooking, I can get the booking informations in the bookings node.

It look pretty easy to do with Sql but I can figure out how to do it with NodeJS.

Here is what I have (in this state, it's impossible to work, but it looks like what I want to do):

async function getReservationsSnapshotByTerminalId(terminalId) {
  const terminalReservationsSnap = await admin.database().ref(`/terminalBookings/${terminalId}`).once('value');
  const terminalReservations = Object.keys(terminalReservationsSnap.val());

  const reservationsSnapshot = terminalReservations.map((reservationId) => {
    return admin.database().ref(`/bookings/${reservationId}`).once('value');
  });

  return Promise.all(reservationsSnapshot);
}

exports.showTerminalsWithReservations = functions.https.onRequest(async (request, response) => {
  let terminals = [];
  try {
    const terminalsSnapshot = await admin.database().ref('/terminals/').once('value');

    terminalsSnapshot.forEach(terminalSnapshot => {
      const terminal = new Borne(terminalSnapshot.key, terminalSnapshot.val());
      const bookingsSnapshot = await getReservationsSnapshotByTerminalId(terminal.key);

      bookingsSnapshot.forEach(booking => {
        terminal.bookings.push(booking.val());
      });
      terminals.push(terminal);
    });
  } catch(error) {

  }
 });

But it can't work because of this line :

const bookingsSnapshot = await getReservationsSnapshotByTerminalId(terminal.key);

If I want to use the await, the parent forEach must by async but it's not possible.

I think that I'm not in the right way to handle this feature but I'm stuck, I don't know how to do it.

Feel free to completely rebuild this function if I'm wrong.

Upvotes: 0

Views: 933

Answers (2)

Reza Nasiri
Reza Nasiri

Reputation: 1435

how about this

const getReservationsSnapshotByTerminalId = (terminalId) => {
     return admin.database().ref(`/terminalBookings/${terminalId}`).once('value')
       .then(snapshot => {
          const terminalReservations = Object.keys(terminalReservationsSnap.val());
          const reservationsSnapshot = terminalReservations.map(reservationId => {
               return admin.database().ref(`/bookings/${reservationId}`).once('value');
       });
       return Promise.all(reservationsSnapshot);
     });
};

exports.showTerminalsWithReservations = functions.https.onRequest(async (request, response) => {
     let terminals = [];
     try {
        terminals = await admin.database().ref('/terminals/').once('value')
           .then(snapshot =>{
               const promises = [];
               const allTerminals = snapshot.val();
               const terminalKeys = Object.keys(allTerminals);
               const terminalsArray = terminalKeys.map(key => new Borne(key, allTerminals[key]));
               promises.push(terminalsArray);
               promises = promises.concat(terminalKeys.map(key => getReservationsSnapshotByTerminalId(key)));
               return Promises.all(promises);
           })
          .then(resultArray => {
               const terminalsArray = resultArray[0];
               terminalsArray.forEach((terminal, idx) => {
                  const bookingsSnapshot = resultArray[idx + 1];
                  bookingsSnapshot.forEach(booking => {
                      terminal.bookings.push(booking.val());
                  });
               });
               return terminalsArray;
         });


} catch(error) {

 }
});

Upvotes: 0

Shubham Chaudhary
Shubham Chaudhary

Reputation: 499

You can achieve that with either of following 2 ways

for await (let terminal of terminals){
   await getReservationsSnapshotByTerminalId(terminal.terminalId);
   console.log(terminalId);
}
console.log("Done");

Output:

Terminal1
Terminal2
Terminal3
Done

OR

var promise = Promise.all(terminals.map((terminal) => {
  console.log(terminal.id);
  return await getReservationsSnapshotByTerminalId(terminal.id);
}));

promise.then(() => console.log("Done"));

Again output is:

Terminal1
Terminal2
Terminal3
Done

Upvotes: 1

Related Questions