1
votes

I'm trying to retrieve an image from Firebase Storage based on the doc id that is retrieved from Firebase Firestore. I am running into an issue because each of these instances returns a Future and requires a separate await/async.

I can't use Future.wait() because I need the first async from the Firestore for the second async, but I also need the second async to start before the first async is complete (which I know isn't how asyncs work). I tried creating a async function within an async function which just behaved as normal (outer async ran first, inner async ran second).

static Future<List<Recipe>> getFirebaseRecipes() async {
    CollectionReference recipesDatabase = FirebaseFirestore.instance.collection('recipes');

    List<Recipe> recipes = new List();
    recipesDatabase.get().then((querySnapshot) => querySnapshot.docs.map((doc) async {
      Reference ref = FirebaseStorage.instance.ref().child('recipeimages');
      String url = await ref.child(doc.id + '.jpg').getDownloadURL();
      recipes.add(Recipe.fromDBMap(doc.id, url, doc.data()));
    }));
        
    return recipes;
}

This is how I was hoping to be able to do it, but obviously cannot use it since there is no async function for the second:

static Future<String> getImageURL(String dbId) async {
    Reference ref = FirebaseStorage.instance.ref().child('recipeimages');
    return await ref.child(dbId + '.jpg').getDownloadURL();
  }

static Future<List<Recipe>> getFirebaseRecipes() async {
    CollectionReference recipesDatabase = FirebaseFirestore.instance.collection('recipes');

    return recipesDatabase.get().then((querySnapshot) => querySnapshot.docs.map((doc) => Recipe.fromDBMap(doc.id, await getImageURL(doc.id), doc.data), doc.data())).toList());
  }

If anyone has any tips or another way on how to retrieve an object from firebase storage (or even how to store and image in Firestore) I would appreciate the help!

1
why don't you store the images download URL to its doc once the upload is finished, that way you don't have to query each time to get its URL - towhid
why cant u use the first snippet? - Peter Haddad
@PeterHaddad I tried to use it but it finishes execution before the second await is finished, so it adds the objects to the list after the return. - user10095235

1 Answers

0
votes

Try the following:

static Future<List<Recipe>> getFirebaseRecipes() async {
    CollectionReference recipesDatabase = FirebaseFirestore.instance.collection('recipes');

    List<Recipe> recipes = new List();
    var querySnapshot = await recipesDatabase.get();
      querySnapshot.docs.map((doc) async {
        Reference ref = FirebaseStorage.instance.ref().child('recipeimages');
        String url = await ref.child(doc.id + '.jpg').getDownloadURL();
        recipes.add(Recipe.fromDBMap(doc.id, url, doc.data()));
     }));   
    return recipes;
}

You need to use await to wait for firestore to retrieve all the data from the database and then you can use the result to get the downloadurl.