How to list favorites/bookmarks in Flutter with Firestore

Viewed 802

I have a collection called Stuff that holds a title. Think it like a Twitter post.

{
    'stuffID': string
    'title': string
    'details': string
}

And I have a favorites collection, that hold who favorite the which post. A user can favorite multiple stuff.

{
    'userID': string
    'stuffID': string
}

From second collection, I want to get all stuffID's that current user favorite. And I want to use those to get rest of the information from first collection. In summary, I want to list all stuff's that user favorite. Like a bookmark list.

I thought I must use two StreamBuilder for achieving this. But I couldn't make it work.

Here is what I manage to do:

  @override
  Widget build(BuildContext context) {
    final FirebaseAuth auth = FirebaseAuth.instance;
    final User? user = auth.currentUser;
    final userID = user!.uid;
    var resultStream = FirebaseFirestore.instance
        .collection('favorites')
        .where("userID", whereIn: [userID]).snapshots();

    return StreamBuilder<QuerySnapshot>(
        stream: resultStream,
        builder:
            (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot1) {
          if (snapshot1.hasError) {
            return Text('Something is wrong.');
          }

          if (snapshot1.connectionState == ConnectionState.waiting) {
            return Text("Loading");
          }
          snapshot1.data!.docs.map((DocumentSnapshot document1) {
            Map<String, dynamic> data1 =
                document1.data()! as Map<String, dynamic>;
            print(data1['stuffID']);
            Query _stuffStream = FirebaseFirestore.instance
                .collection('Stuffs')
                .where('stuffID', isEqualTo: data1['stuffID']);
            return StreamBuilder<QuerySnapshot>(
                stream: _stuffStream.snapshots(),
                builder: (BuildContext context,
                    AsyncSnapshot<QuerySnapshot> snapshot2) {
                  if (snapshot2.hasError) {
                    return Text('Something is wrong.');
                  }

                  if (snapshot2.connectionState == ConnectionState.waiting) {
                    return Text("Loading");
                  }

                  return ListView(
                    //showing the data
                    children:
                        snapshot2.data!.docs.map((DocumentSnapshot document) {
                      Map<String, dynamic> data =
                          document.data()! as Map<String, dynamic>;
                      String stuffID = data['stuffID'];
                      return ListTile(
                        title: Text(data['title']),
                        subtitle: Text(data['details']),
                      );
                    }).toList(),
                  );
                });
          });
          return const Center(child: CircularProgressIndicator());
        });
  }

When I use this code, app stucks at loading screen: enter image description here

I'm trying to work it for two days but all my attempts have failed. Can you please help?

1 Answers

I did more and more research day after day and found the answer. I created the code based on here. Note that I changed the design of my collection in Firebase. But it completely unrelated to rest of code. I just wanted to go with more efficient way to store the data.

In summary, I'm fetching the stuffID from favorites collection. And using that stuffID to get stuffs.

@override
  Widget build(BuildContext context) {
    final FirebaseAuth auth = FirebaseAuth.instance;
    final User? user = auth.currentUser;
    final userID = user!.uid;

    return StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance
          .collection('favorites')
          .doc(userID)
          .collection(userID)
          .snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) return const Text("Loadsing...");
        return Column(children: [
          ListView.builder(
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: snapshot.data!.docs.length,
              itemBuilder: (context, index) {
                //return buildListItem(context, snapshot.data.documents[index]);
                return ListView(
                  scrollDirection: Axis.vertical,
                  shrinkWrap: true,
                  children: <Widget>[
                    StreamBuilder<QuerySnapshot>(
                        stream: FirebaseFirestore.instance
                            .collection('Stuffs')
                            .where('stuffID',
                                isEqualTo: snapshot.data!.docs[index]
                                    ['stuffID']) //seçilen döküman
                            .snapshots(),
                        builder: (context, snap) {
                          if (!snap.hasData) return const Text("Loading...");
                          return ListTile(
                            leading: CircleAvatar(
                              backgroundImage: NetworkImage(
                                  snap.data!.docs[index]['stuffImage']),
                            ),
                            title: Text(snap.data!.docs[index]['title']),
                            subtitle: Column(
                              children: <Widget>[
                                Text(snap.data!.docs[index]['details']),
                              ],
                            ),
                          );
                        }),
                  ],
                );
              }),
        ]);
      },
    );
  }
Related