1

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]);
  }
Doug Stevenson
  • 268,359
  • 30
  • 341
  • 380
Jithin Joy
  • 155
  • 2
  • 12

2 Answers2

2

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.

dumazy
  • 12,758
  • 12
  • 60
  • 107
-2

I think it's better to use serial where clauses.

Stream stream = FirebaseFirestore.instance.collection("Gyms").where('gymPlaceTags',  arrayContainsAny: ["dubai"]).where("gymFavTags", arrayContainsAny: ["ajman"]).orderBy('createdAt', descending: true).snapshots();

This type of query has worked for me. Hope this will solve your problem.

  • You can use at most one in, not-in, or array-contains-any clause per query. You can't combine in, not-in, and array-contains-any in the same query. – Jithin Joy Jul 15 '21 at 06:46
  • I have used two isEqualTo clauses in my app and it has worked fine. I have never used two whereIn clauses. My bad. Below is my example. FirebaseFirestore.instance.collection('SubjectGroup').where('degree', isEqualTo: degree).where('year', isEqualTo: year).get() – Melanga Dissanayake Aug 23 '21 at 13:16