Merging multiple firebase stream in flutter

252 Views Asked by At

Guy this is a real problem merging multiple firebase streams to one stream. Someone should write an article or a simple video tutorial on this. Either using StreamGroup, FlatMap(), Rx.combineLatest, StreamZip or CombineLatestesStream. I have tried solving this since yesterday and I cant get a clear guidance.

class CartPage extends StatefulWidget{
   @override
   _CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
   
   // a firebase collection for all items
   Stream stream1 = EcommerceApp.firestore
    .collection("items")
    .where("shortInfo",
        whereIn: EcommerceApp.sharedPreferences
            .getStringList(EcommerceApp.userCartList))
    .snapshots();

   // a firebase collection for flash sales items
   Stream stream2 = EcommerceApp.firestore
    .collection("flashitem")
    .where("shortInfo",
        whereIn: EcommerceApp.sharedPreferences
            .getStringList(EcommerceApp.userCartList))
    .snapshots();

   List<QuerySnapshot> getList(QuerySnapshot list1) {
   List<QuerySnapshot> result = [];
   (list1 as List).forEach((element) {
     result.add(element);
    });
     return result;
   }

 @override
 Widget build(BuildContext context) {

  Stream combineStream = Rx.combineLatest2(streamA, streamB, (a, b) => [a, b]);


   return Scaffold(
    appBar: MyAppBar(),
    body:CustomScrollView(
      slivers: [
        SliverToBoxAdapter(
          child: Container(
            height: 10.0,
          ),
        ),
       StreamBulder(
       stream: combineStream,
        builder: (context, snapshot) {
              if (!snapshot.hasData) {
                return SliverToBoxAdapter(
                  child: Center(
                    child: circularProgressBar(),
                  ),
                );
              } else {
              List<QuerySnapshot> _list = [];
                _list.addAll(getList(snapshot.data[0]));
                _list.addAll(getList(snapshot.data[1]));
                if (_list.length == 0) {
                } else {
                  return SliverList(
                    delegate: SliverChildBuilderDelegate(
                      (context, index) {
                        ProductModel model = ProductModel.fromJson(
                           _list[index].docs[index].data());

                        return cartSourceInfo(model, context,
                            removeCartFunction: () =>
                                removeItemFromUserCart(model.shortInfo));
                      },
                      childCount: childCount: snapshot.hasData ? _list.length : 0,
                    ),
                  );
                }
              }
            }    
       )
    );
 }
}

Majority of the answers here are using Observable library which is deplecated in rxdart, and when am trying to use the same syntax to solve using Rx.latestCombine2 there is no data streamed. and when I try to pass a querySnapshot of type list to a stream Stream<List> I am getting a batch of errors:

Class 'List' has no instance getter 'docs'. Receiver: Instance(length:2) of '_GrowableList' Tried calling: docs

Please show me how I can either nest these two firebase stream into ome or how I can use Rx.combineLatest2 method to solve this problem.

1

There are 1 best solutions below

11
On

The syntax looks correct but when trying to access data of each stream you have to access it by index since the snapshot is basically a list

so to access snapshot of stream1 and stream2 it should be accesssed like this

snapshot.data[0].docs and snapshot.data[1].docs respectively.

You can combine both the streams and show the list in the Ui, And make sure to assign a appropriate type T based on the type of snapshot.data[index].docs


 List<QuerySnapshot> combineLists(
      List<QuerySnapshot> list1, List<QuerySnapshot> list2) {
    List<QuerySnapshot> result = [];
    list1.forEach((element) {
      result.add(element);
    });
    list2.forEach((element) {
      result.add(element);
    });
    return result;
  }

StreamBulder(
 ​stream: combineStream,
 ​builder: (context, AsyncSnapshot<List<QuerySnapshot>> snapshot) {
   ​if (!snapshot.hasData) {
      ​return SliverToBoxAdapter(
        ​child: Center(
          ​child: circularProgressBar(),
          ​),
        ​);
      ​} else {​
         final List<QuerySnapshot> _list=[];
         final List<QuerySnapshot> combineSnapshot =
                    combineLists(snapshot.data[0], snapshot.data[1]);
         ​if (_list.length == 0) {
            ​return addItems();
         ​} else {
             return SliverList(
                ​delegate: SliverChildBuilderDelegate(
                (context, index) {
                     ProductModel model = ProductModel.fromJson(
                     _list[index].data());
                 return cartSourceInfo(model, context, removeCartFunction: 
                    () => removeItemFromUserCart(model.shortInfo));
                 ​},
                 childCount:_list.length,
                 ),
               );
           ​}
        }
   }