Skip to content
Advertisement

problems with an array awaiting for a function that reads from firestore

I’m trying to build a method which reads from firestore an array of elements (object):

I have a service which retrieves the data from firestore, first it gets an array of document references

var data = snapshot.get(‘elements’);

and then it gets all the objects:

getElements(){
return new Promise(res =>{
  this.AngularAuth.currentUser
  .then( user => {
    this.useruid = user.uid;
    this.db.firestore.doc(`/users/${this.useruid}`).get().then(snapshot =>{
      if(snapshot.exists){
        var data = snapshot.get('elements'); //This gets the array of elements
        data.forEach(element => {
          this.db.firestore.doc(element).get().then(object =>{
            if(object.exists){
              var elem = object.data() as object;
              this.array.push(elem);//I kind of push in the array instances of object
            }
            else{
              console.log("Error. Doc doesn't exist")
            } 
          }).catch(err =>{
            console.log(err);
          })
        });
        res(this.array);
      }
      else{
        console.log("Error. Doc doesn't exist")
      }        
    }).catch(function(error) {
      // An error happened.
    })
  })
  .catch(function(error) {
    // An error happened.
  })
});

}

Then in a component I have an async method which calls the service, and tries to push into another array all the names from each object in the first array:

async retrieveArray(){
this.array = await this.service.getElements();
this.array.forEach(element => {
  this.names.push(element.name);
});
console.log(this.array);
console.log(this.names);
}

However when I look to the console, the first array (array) gives me indeed an array of objects, but the other array (names) is empty. I used the method get to retrieve the data because I don’t want to listen to it, I might need the value just once.

Advertisement

Answer

Personally I find the async/await syntax infinitely more elegant and easier to deal with than a good old .then() callback hell :

async getElements() {

    let user;
    try{
        user = await this.AngularAuth.currentUser();
    } catch(err) {
        console.log(err);
        return;
    }

    this.useruid = user.uid;
    const snapshot = await this.db.firestore.doc(`/users/${this.useruid}`).get();

    if (!snapshot.exists) {
        console.log("Error. Doc doesn't exist")
        return
    }

    const data = snapshot.get('elements'); //This gets the array of elements

    let toReturn = [];

    for(let element of data){ // can also use 'await Promise.all()' here instead of for...of
        const object = await this.db.firestore.doc(element).get();
        toReturn.push(elem);
    }

    return toReturn;
}


async retrieveArray(){
    this.array = await this.service.getElements();
    this.names = this.array.map( element => element.name ) // Also use .map() here
    console.log(this.array);
    console.log(this.names);
 }

If you use for...of, all calls will be made one after the other, in order. If you use await Promise.all(), all calls will be made and awaited simultaneously, which is faster but recommended only if you have a small number of calls to make (otherwise this could overload the server you’re calling, or even be considered as a DDoS attack.)

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement