Wondering
Wondering

Reputation: 11

Firebase - Get data from two collections at once

Hi StackOverflow Community,

I am trying to access values from my Firestore database located in two different collections.

  1. I could retrieve data from the first collection through a StreamBuilder without any problems.
  2. However, I cannnot retrieve data from the second collection. I want to get the data through a where query within a second StreamBuilder but I can't access the values... I only get StreamBuilder<QuerySnapshot<Object?>> returned.

How can I also access values from my second collection as well? Thank you in advance!

Here is my code:

 Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot> (
        stream: _firestore
            .collection('customers')
            .doc(user!.uid)
            .collection('cart')
            .snapshots(),
        builder: (context, snapshot){
          if(snapshot.hasData){
            final cart = snapshot.data!.docs;
            List<Column> cartWidgets = [];
            List<String> ids = [];
            for (var product in cart) {
              final productCount = product['count'];
              final productID = product['id'];

              final productPrice = StreamBuilder<QuerySnapshot>(
                stream: _firestore.collection('product')
                        .where('id', isEqualTo: productID)
                        .snapshots(),
                  builder: (context, snapshot) {
                  if(!snapshot.hasData){
                    return Text('Something went wrong...');
                  } else{
                    final products = snapshot.data!.docs;
                    final productPrice = products.first['price'];
                    return Text(productPrice.toString());
                  }
                  }
              );

              final productWidget = Column(
                  children: [
                    Text('Quantity: $productCount'),
                    Text('ProductID: $productID'),
                    Text('Price: $productPrice'),
                    SizedBox(height: 50,)
                  ]
              );
              cartWidgets.add(productWidget);
            }
            return SingleChildScrollView(
              child: SafeArea(
                child: Column(
                  children: cartWidgets,
                ),
              ),
            );
          } else{
            return const Center(
              child: const CircularProgressIndicator(
                backgroundColor: Colors.lightBlueAccent,
              ),
            );
          }
        }
    );
  }

Emulator: Emulator

Firestore: First Collection: Works without problems

Second collection: Cannot access data from here as second source

Upvotes: 1

Views: 1078

Answers (1)

Mohammed Ali
Mohammed Ali

Reputation: 145

you can use "Rx" to combine 2 streams

Stream<List<DocumentSnapshot>> combine2Streams( 
  Stream<DocumentSnapshot> stream1,
  Stream<QuerySnapshot> stream2) { 

     return Rx.combineLatest2( 
     stream1,
     stream2,
     (DocumentSnapshot a, QuerySnapshot b) => List.from(a.documents)..addAll(b.documents));
 } 

your code will be

Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot> (
        stream: combine2Streams(
           _firestore
            .collection('customers')
            .doc(user!.uid).snapshots(),
           _firestore
            .collection('cart').snapshots()
         ),
        builder: (context, snapshot){
          if(snapshot.hasData){
            final cart = snapshot.data!.docs;
            List<Column> cartWidgets = [];
            List<String> ids = [];
            for (var product in cart) {
              final productCount = product['count'];
              final productID = product['id'];

              final productPrice = StreamBuilder<QuerySnapshot>(
                stream: _firestore.collection('product')
                        .where('id', isEqualTo: productID)
                        .snapshots(),
                  builder: (context, snapshot) {
                  if(!snapshot.hasData){
                    return Text('Something went wrong...');
                  } else{
                    final products = snapshot.data!.docs;
                    final productPrice = products.first['price'];
                    return Text(productPrice.toString());
                  }
                  }
              );

              final productWidget = Column(
                  children: [
                    Text('Quantity: $productCount'),
                    Text('ProductID: $productID'),
                    Text('Price: $productPrice'),
                    SizedBox(height: 50,)
                  ]
              );
              cartWidgets.add(productWidget);
            }
            return SingleChildScrollView(
              child: SafeArea(
                child: Column(
                  children: cartWidgets,
                ),
              ),
            );
          } else{
            return const Center(
              child: const CircularProgressIndicator(
                backgroundColor: Colors.lightBlueAccent,
              ),
            );
          }
        }
    );
  }

Upvotes: 1

Related Questions