Search code examples
flutterdartgoogle-cloud-firestorestream-builder

Flutter Retrieving firestore collection using Stream


I am trying to retrieve a whole collection in firestore using StreamBuilder but I got stuck in mapping the result according to my dart model

This is the dart model thread.dart:

class Thread {
  final String threadTitle;
  final String threadContent;
  final String threadFlair;
  final String threadTimestamp;
  final List<String> threadLikedBy;
  final List<String> originalPoster;

  Thread({
    this.threadTitle,
    this.threadContent,
    this.threadTimestamp,
    this.threadFlair,
    this.threadLikedBy,
    this.originalPoster,
  });

  factory Thread.fromMap(Map<String, dynamic> map) => Thread(
    threadTitle: map["threadTitle"],
    threadContent: map["threadContent"],
    threadFlair: map["threadFlair"],
    threadTimestamp: map["threadTimestamp"],
    threadLikedBy: List<String>.from(map["threadLikedBy"].map((x) => x)),
    originalPoster: List<String>.from(map["originalPoster"].map((x) => x)),
  );

  Map<String, dynamic> toMap() => {
    "threadTitle": threadTitle,
    "threadContent": threadContent,
    "threadFlair": threadFlair,
    "threadTimestamp": threadTimestamp,
    "threadLikedBy": List<dynamic>.from(threadLikedBy.map((x) => x)),
    "originalPoster": List<dynamic>.from(originalPoster.map((x) => x)),
  };
}

This is the widget where I display the results in a listview:

class _ThreadsBodyState extends State<ThreadsBody> {
  final threads = _mThreadService.retriveData(path: "posts", builder: (data) => Thread.fromMap(data));
  @override
  Widget build(BuildContext context) {
    return Container(
      child: StreamBuilder<Object>(
        stream: threads,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              itemBuilder: (BuildContext context, int index) {
                Thread thrd = (snapshot.data as List)[index];
                return ThreadCard(thread: thrd,);
              },
            );
           } else {return Text('no data');}
      }),
    );
  }
}

and here's posts_service.dart where I have the Stream function

//After restructuring my model and adding: 
//List<String> threadLikedBy; and List<String> originalPoster;
//this method works no more

Stream<List<T>> retrieveData<T>({
  @required String path,
  @required T builder(Map<String, dynamic> data),
}) {
  final reference = firestoreInstance.collection(path);
  final snapshots = reference.snapshots();
  return snapshots.map((snapshot) => snapshot.docs.map((snapshot) => builder(snapshot.data())).toList());
}

It appears to be that I am messing up the mapping in the return but I can't exactly figure out how to fix it.


Solution

  • in your 'posts_services.dart' add the following function:

    Future<QuerySnapshot> fetchThreads() async {
        return await firestoreInstance.collection('posts').get();
    }
    

    Now in your widget where you build your ListView should look like this:

    class _ThreadsBodyState extends State<ThreadsBody> {
      @override
      Widget build(BuildContext context) {
        return Container(
          child: FutureBuilder<QuerySnapshot>(
            future: youService.fetchThreads(),
            builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                  itemCount: snapshot.data.size, //to retrieve the size
                  itemBuilder: (BuildContext context, int index) {
                    Thread thrd = Thread.fromMap(snapshot.data.docs[index].data());
                    return ThreadCard(thread: thrd,);
                  },
                );
               } else {return Text('no data');}
          }),
        );
      }
    }