0

I need that the function _get_datos_restaurante() waits to the other functions (_get_nombre_provincia() and _get_valoracion_media() ) ends, but I can't achieve that. The issue is the variable valoracion_media is not correctly "operated" when _get_datos_restaurate() ends. The functions are asynchronous and I am using _get_datos_restaurante() in a FutureBuilder, so I don't know what it's the error. Here is my code:

Future<void> _get_datos_restaurante(String id, QueryDocumentSnapshot r) async {
 await _get_nombre_provincia(id);
  await _get_valoracion_media(r);
  print(valoracion_media);
}

Future<void> _get_nombre_provincia(String id) async {
  await firestoreInstance.collection('Provincia').doc(id).get().then((value) => nombreProvincia = value.get('nombre'));
}

Future<void> _get_valoracion_media(QueryDocumentSnapshot r) async {
  List<dynamic> id_valoraciones = r.get('valoraciones');
  List<double> nota_valoraciones = [];
  id_valoraciones.forEach((v) async {
    await firestoreInstance.collection('Valoracion_Restaurante').doc(v).get().then((value) { 
      nota_valoraciones.add(value.get('nota'));
  });});
  nota_valoraciones.forEach((n) =>valoracion_media+=n);
  valoracion_media = valoracion_media/nota_valoraciones.length;  
}
deslarry
  • 31
  • 1
  • 6
  • 1
    https://stackoverflow.com/questions/63719374/how-to-wait-for-foreach-to-complete-with-asynchronous-callbacks/63719805#63719805 – pskink Mar 16 '22 at 13:02

2 Answers2

2

Use a for loop instead of forEach like so:

 for(final v in  id_valoraciones){
   final x = await firestoreInstance.collection('Valoracion_Restaurante').doc(v).get();
   nota_valoraciones.add(x.get('nota'));
 }
Josteve
  • 11,459
  • 1
  • 23
  • 35
  • This is a great answer! Notice that this gets one document at a time whereas [my answer](https://stackoverflow.com/a/71497611/1080564) parallelizes getting the documents, so it may take less time but may also stress the system more if there are lots of documents. Use whatever fits your use case :-) – Niels Abildgaard Mar 16 '22 at 13:15
1

You have a forEach loop where you iterate over id_valoraciones which cannot wait for Futures to complete.

In order to wait for several futures at once, you can use Future.wait, which waits for several futures to complete and collect the results.

You can use map for turning a list of items into a list of Futures, which can then be waited for.

nota_valoractiones = await Future.wait(id_valoraciones.map((v) async {
  const value = await firestoreInstance.collection('Valoracion_Restaurante').doc(v).get();
  return value.get('nota');
});

This code can be broken down as follows:

  • For each entry in id_valoraciones, create a Future that...
    • Gets a document value from firestore
    • Returns the nota field from that document
  • Waits for all the Futures to complete, saving the results of them in the list nota_valoractiones.

In other words, the Futures execute in parallel.

As highlighted by @pskink in a comment to the question, you can also use Future.forEach to perform an asynchronous action for each entry in a list. Note, however, that Future.forEach does not execute in parallel.

Niels Abildgaard
  • 2,662
  • 3
  • 24
  • 32