How to return list of object in a stream on flutter

Talha picture Talha · Dec 25, 2018 · Viewed 7.3k times · Source

I have below firestore structure and a method to get user feed from DB.

I need to chain my stream like

  1. First all feed ID from User/FeedIDs collection

  2. Then for every feedID, get documents for the feed details and return back to list of them.

I could find a way to solve this because toList() is not working or i am doing something wrong.

// User Collection
- User
   - RandomDocumentID
      - Feed
         - FeedIDasDocumentID
           - field1
           - field2
             .
             .

// Feed Collection
- Feed
   - RandomDocumentID
      - field1
      - field2
        .
        .

// Method in my repository to get feed for User
Observable<Feed> getCurrentUserFeed(String uid) {
    return Observable(Firestore.instance
          .collection('User')
          .document(uid)
          .collection("FeedIDs")
          .snapshots()
          .expand((snapshots) => snapshots.documents)
          .map((document) => UserFeed.fromMap(document.data))
        )
        .flatMap((userFeed) => Firestore.instance
                               .collection("Feed")
                               .document(userFeed.id)
                               .snapshots()
        )
        .map((document) => Feed.fromMap(document.data));
        // ????
        // I tried to put .toList() and of the stream but it is not working, 
       // i wanna return List<Feed> instead of every single feed object
  }


// in my BLoC
// I had to do that because I could acquire to get streams elements as a list
// 
List<Feed> feedList = List();
FirebaseUser user = await _feedRepository.getFirebaseUser();
_feedRepository.getCurrentUserFeed(user.uid).listen((feed) {
    feedList.add(feed);
    dispatch(UserFeedResultEvent(feedList));
 };

If there is any other approach for chaining, it will be really appreciated to share. Thank you

Answer

Nate Bosch picture Nate Bosch · Jan 4, 2019

I think the issue here is that Firestore is set up to send updates whenever records change. When you query for snapshots it's a Stream that will never send a done event, because new updates could always come in.

Some of the methods on Stream that return a Future will never complete if the stream does not send a done event. These include .single and .toList(). You are probably looking for .first which will complete after the first event is sent through the stream (the current state of the records in the database) and stop listening for changes.