Reputation: 85
I'm trying to collect data from different documents of different collections, and doing it in a for loop increase the code processing time
for (var i = 0; i < productDataList.length; i++) {
// Get full data according to shared preferences
var firestore = FirebaseFirestore.instance;
DocumentSnapshot ds1 = await firestore
.collection('products')
.doc(productDataList[i][4])
.collection(productDataList[i][4])
.doc(productDataList[i][0])
.get();
// Add product DocumentSnapshot to map
productFullDetails.add({'productDoc': ds1});
}
Does anyone know a better method to do this? Thank you.
Upvotes: 0
Views: 386
Reputation: 7686
You can move the asynchronous operation out of the for-loop by creating a list of the async operations Futures and getting all the results at once by using Future.wait.
var firestore = FirebaseFirestore.instance;
final List<Future<DocumentSnapshot>> documentSnapshotFutureList =
productDataList
.map((productData) => firestore
.collection('products')
.doc(productDataList[i][4])
.collection(productDataList[i][4])
.doc(productDataList[i][0])
.get())
.toList();
final List<DocumentSnapshot> documentSnapshotList = await Future.wait(documentSnapshotFutureList);
productFullDetails = documentSnapshotList
.map((DocumentSnapshot documentSnapshot) =>
{'productDoc': documentSnapshot})
.toList();
Note the following with using Future.wait
,
Returns a future which will complete once all the provided futures have completed, either with their results, or with an error if any of the provided futures fail.
The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures
Upvotes: 1
Reputation: 12353
The problem is not caused by the for loop per se, look into what is happening in the for loop. If you making an asynchronous network request and awaiting for it. If you have a list of products that is 100 items long, you have to make 100 requests, and wait for each one to finish. If every request was 200 milliseconds[which is not slow], that's 20 seconds.
I would probably skip doing it in a for loop, and use a stream builder to get every single document in a stream by it's self, which is technically the same amount of reads.
Use your for loop to create a steam, pseudo code will look like this:
Column(
children:[
for (var product in productDataList)
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('products')
.doc(product[4])
.collection(product[4])
.doc(product[0])
.snapshots(),
builder: (context, snapshot){
if(snapshot.hasData) productFullDetails.add({'productDoc': snapshot.data() as Map<String,dynamic>});
return Text('something');
}
)
])
This will get your data simultaneously, without having to await for them to finish after one another.
Upvotes: 1