How to get data from two collections in firebase using Flutter

Viewed 1895

This is my problem:

I have a ListPost StatefulWidget where I want to display a list of widgets that contains the user's account image, the user's name, and the user's posts images(similar to Facebook feeds), however, I have gotten to the point that I need to get that data from two different collections in Firebase (see my firebase collections image below).

The good thing is that I have been able to get that data only from one collection(userFeed) and display that data in my ListPost file in different widgets, however, I do not know how to get data from another collection in Firebase using the same streamBuilder and display all that data I want to display in other widgets in my ListPost screen.

So, my specific question is: How can I make my ListPost screen to populate data from 2 different collections in Firebase using a stream builder or another type of implementation?

This is the firebase image

enter image description here

This is the complete code for the ListPost screen

import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'models/post_model.dart';

final _stream = Firestore.instance.collection('userFeed').snapshots();

class ListPosts extends StatefulWidget {

  @override
  _ListPostsState createState() => _ListPostsState();
}

class _ListPostsState extends State<ListPosts> {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        //this is the Streambuilder to get the data however it only lets me to get one collection
        child: StreamBuilder(
          stream: _stream,
          builder: (context, snapshot) {
            if (!snapshot.hasData) return const Text('Loading...');
            return ListView.builder(
              itemExtent: 550.0,
              itemCount: snapshot.data.documents.length,
              itemBuilder: (BuildContext context, int data) {
                //here I get the data from the userFeed colecction
                Post post = Post.fromDoc(snapshot.data.documents[data]);
                return Column(
                  children: <Widget>[
                    GestureDetector(
                      child: Container(
                        padding: EdgeInsets.symmetric(
                          horizontal: 16.0,
                          vertical: 10.0,
                        ),
                        child: Row(
                          children: <Widget>[
                            CircleAvatar(
                              radius: 25.0,
                              backgroundColor: Colors.grey,
                              backgroundImage: post.imageUrl.isEmpty
                                  ? AssetImage(
                                      'assets/images/user_placeholder.jpg')
                                  : CachedNetworkImageProvider(post.imageUrl),
                            ),
                            SizedBox(width: 8.0),
                            Text(
                              post.caption,
                              style: TextStyle(
                                fontSize: 18.0,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                    GestureDetector(
                      child: Stack(
                        alignment: Alignment.center,
                        children: <Widget>[
                          Container(
                            height: MediaQuery.of(context).size.width,
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image:
                                    CachedNetworkImageProvider(post.imageUrl),
                                fit: BoxFit.cover,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                );
              },
            );
          },
        ),
      ),
    );
  }
}

UPDATE 05-22-2020 HOW I FIXED THE ISSUE Credits to the user griffins, he helped me to fix this issue.

This is what I do:

I nested my StreamBuilder so I can use 2 streams at the same time

 return StreamBuilder(
      stream: _stream,
      builder: (context, snapshot1) {
        return StreamBuilder(
          stream: _stream2,
          builder: (context, snapshot2) {
            if (!snapshot2.hasData) return const Text('Loading...');
            if (!snapshot1.hasData) return const Text('Loading...');
            return ListView.builder(
              itemExtent: 550.0,
              itemCount: snapshot2.data.documents.length,
              itemBuilder: (BuildContext context, int data) {
                User user = User.fromDoc(snapshot2.data.documents[data]);
                Post post = Post.fromDoc(snapshot1.data.documents[data]);
                return buildbody(user, post, context);
              },
            );
          },
        );
      },
    );
1 Answers

You can can make you body take a widget ListView and for the Listview children have both your lists.

example

body: ListView(
          children: <Widget>[
           ---list1----

            --list2-----   
          ]);

or you can use a custom scroll view

return new Scaffold(
    appBar: new AppBar(
        title: new Text("Project Details"),
        backgroundColor: Colors.blue[800]),
    body:
    new CustomScrollView(
        slivers: <Widget>[
          new SliverPadding(padding: const EdgeInsets.only(left: 10.0,right: 10.0,
              top: 10.0,bottom: 0.0),
            sliver: new SliverList(delegate:
            new SliverChildListDelegate(getTopWidgets())),
          ),
          new SliverPadding(padding: const EdgeInsets.all(10.0),
              sliver: new SliverList(delegate: new SliverChildListDelegate(
                  getSfListTiles()
              ))),
          new SliverPadding(padding: const EdgeInsets.all(10.0),
              sliver: new SliverList(delegate: new SliverChildListDelegate(
                  getWorkStatementTiles()
              ))),
        ]
    )

);

update from @Rémi Rousselet answer You can nest StreamBuilder

    StreamBuilder(
  stream: stream1,
  builder: (context, snapshot1) {
    return StreamBuilder(
      stream: stream2,
      builder: (context, snapshot2) {
        // do some stuff with both streams here
      },
    );
  },
)
Related