Search code examples
flutterdartgoogle-cloud-firestorestreamsnapshot

How to merge two firestore queries in the Flutter project and How do I remove the duplicate documents from these two streams?


I needed to combine two firestore query stream in my flutter project. How do I do this? I tried StreamZip([Stream1, stream2]) method to combine the streams and it worked for me. but the streams maybe contains the same documents. so when I listed them all of the documents are listed, even there is a duplicate of it. How do I remove the duplicate documents from these two streams?

   Stream<List<QuerySnapshot>> getData() {
    Stream defaultStream1 = _firestore
        .collection("Gyms")
        .where("gymPlaceTags", arrayContainsAny: ["dubai"])
        .orderBy('createdAt', descending: true)
        .snapshots();
    Stream defaultStream2 = _firestore
        .collection("Gyms")
        .where("gymFavTags", arrayContainsAny: ["ajman"])
        .orderBy('createdAt', descending: true)
        .snapshots();
    return StreamZip([defaultStream1, defaultStream2]);
  }

Solution

  • There are several steps you'll need to take:

    1. map the stream to return another a List<DocumentSnapshot> instead of List<QuerySnapshot>
    2. In the map function, use fold on the List to remove duplicates and map to List<DocumentSnapshot>
    3. In the fold function, go over every document in the QuerySnapshot and check if the document with the same id is already present before adding.

      Stream<List<DocumentSnapshot>> merge(Stream<List<QuerySnapshot>> streamFromStreamZip) {
        return streamFromStreamZip.map((List<QuerySnapshot> list) {
          return list.fold([], (distinctList, snapshot) {
            snapshot.documents.forEach((DocumentSnapshot doc) {
              final newDocument = distinctList.firstWhere(
                      (DocumentSnapshot listed) =>
                          listed.documentId == doc.documentId,
                      orElse: () => null) == null;
              if (newDocument) {
                distinctList.add(doc);
              }
            });
            return distinctList;
          });
        });
      }
      

      Note: I didn't run this code, but it should be something like this.