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.)