Solved: Flutter Firebase Merge Streams List with CombineLatestStream and Display on StreamBuilder

Question

Asked by Rkdio on December 18, 2021 (source).

I have a combine list of streams like that;

var Ref1 = _firestore
      .collectionGroup("Posts")
      .where('postID', whereIn: List1)
      .snapshots();
  var Ref2 = _firestore
      .collectionGroup("Posts")
      .where('postID', whereIn: List2)
      .snapshots();
  var Ref3 = _firestore
      .collectionGroup("Posts")
      .where('postID', whereIn: List3)
      .snapshots();
  
  List<Stream<QuerySnapshot>> combineList = [Ref1, Ref2, Ref3];

And with this method I merge the Streams from the combineList;

var totalRef = Rx.combineLatest(
    combineList, (list) => (list as Iterable<Iterable>).flattened);

Then I use totalRef inside StreamBuilder.

StreamBuilder<QuerySnapshot>(
                      stream: totalRef,
                      builder:
                          (BuildContext context, AsyncSnapshot asyncsnapshot) {
                        if (asyncsnapshot.hasError) {
                          return Center(
                            child: Text("Error"),
                          );
                        } else {
                          if (asyncsnapshot.hasData) {
                            List<DocumentSnapshot> listOfDocumentSnapshot =
                                asyncsnapshot.data.docs;
                            return ListView.builder(
                              physics: ScrollPhysics(),
                              shrinkWrap: true,
                              itemCount: listOfDocumentSnapshot.length,
                              itemBuilder: (BuildContext context, int index) {
                                return Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 12.0, vertical: 12.0),
                                  child: Container(
                                    child: Column(
                                      children: <Widget>[
                                        Stack(
                                          children: <Widget>[
                                            Align(
                                              alignment: Alignment.topCenter,
                                              child: ClipRRect(
                                                borderRadius:
                                                BorderRadius.circular(24),
                                                child: GestureDetector(
                                                  onTap: () => navigateToDetail(
                                                      listOfDocumentSnapshot[
                                                      index]),
                                                  child: Image(
                                                    height: 320,
                                                    width: 320,
                                                    fit: BoxFit.cover,
                                                    image: NetworkImage(
                                                        listOfDocumentSnapshot[
                                                        index]["photo"]),
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ],
                                        ),
                                      ],
                                    ),
                                  ),
                                );
                              },
                            );
                          }
                           else {
                            return Center(
                              child: CircularProgressIndicator(
                                color: Colors.orangeAccent[400],
                              ),
                            );
                          }
                        }
                      },
                    ),

I'm also listing the snapshot data that comes in StreamBuilder;

List<QuerySnapshot> querySnapshot =
                                asyncsnapshot.data.toList();

                            List<DocumentSnapshot> listOfDocumentSnapshot = [];

                            querySnapshot.forEach((query) {
                              listOfDocumentSnapshot.addAll(query.docs);
                            });

When I use totalRef in StreamBuilder, I'm running into an error like this;

type 'CombineLatestStream<QuerySnapshot<Object>, Iterable<dynamic>>' is not a subtype of type 'Stream<QuerySnapshot<Object?>>?

My question is clear, but to summarize briefly, I have a list of streams named combineList, the number of streams in this list is completely dependent on the user, so the number of streams varies from user to user, I need to combine this combineList and print it as a single stream in StreamBuilder. The best way I've found is the CombineLatestStream method for now, but I'm getting the error I mentioned when calling it in StreamBuilder.

I've been dealing with this for days. Once I got the error that the whereIN query is limited to only 10 values. When I learned this, I learned that I had to query the streams separately and then merge them. I queried the streams separately, I merge them with StreamGroup.merge and Rx.merge methods, after I combined them with StreamGroup.merge and Rx.merge methods. I got error. After getting error I learned that I need to merge Streams with the combineLatest method and now I'm getting this error.

Please, someone who knows the answer or has encountered this problem before, write the appropriate solution for my code, all the information about the code is already above, if you want me to give more information, I can edit the question.

Answer

Question answered by Rkdio (source).

After much effort, I solved my problem. My answer for those who have the same problem.

First of all, I realized that I had combined the stream list named combineList incorrectly, so I changed my merge method like this:

var totalRef = CombineLatestStream.list(combineList);

Then I changed the StreamBuilder design:

StreamBuilder<List<QuerySnapshot>>(
                      stream: totalRef,
                      builder: (BuildContext context,
                          AsyncSnapshot<List<QuerySnapshot>> snapshotList) {} )

So I converted a StreamBuilder from a query snapshot to a StreamBuilder from a list of query snapshots.

Then, in builder; in order to access the data in the snapshot list, I converted this snapshots into a data type and defined it in a listOfDocumentSnapshot list.

List<QuerySnapshot> querySnapshot =
                                snapshotList.data;

                            List<DocumentSnapshot> listOfDocumentSnapshot = [];

                            querySnapshot.forEach((query) {
                              listOfDocumentSnapshot.addAll(query.docs);
                            });

The itemCount in ListView.builder naturally became like this: listOfDocumentSnapshot.length,

Then I was able to call each data by index number in ListView.builder.

FIREBASE FLUTTER GOOGLE-CLOUD-FIRESTORE
SHARE: