Thaanu
Thaanu

Reputation: 85

How to get Firestore data from documents of different collections

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

Answers (2)

Victor Eronmosele
Victor Eronmosele

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

https://api.flutter.dev/flutter/dart-async/Future/wait.html

Upvotes: 1

Huthaifa Muayyad
Huthaifa Muayyad

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

Related Questions