How to return a Stream using an async* function in Flutter

Issue

I am working on a chat app using Flutter and Firebase. I am new to Dart and so got stuck when I wanted to create a function which fetches (using await) a particular document from one collection (forums) and use an array property of the forum document to query and return a Stream from another collection (openMessages). The problem with my current solution is that it always returns an empty array. I am sure I am using the keywords or logic incorrectly. Can you please help me refactor my method.

Stream<List<ChatMessage>> getForumChatStream(String forumId) async* {
List<ChatMessage> messages = [];
var docSnap = await firestore.collection('forums').doc(forumId).get();
Forum forum = Forum.fromMap(docSnap.data()!);

firestore
    .collection('openMessages')
    .where('messageId', whereIn: forum.messageIds) 
    .orderBy('timeSent', descending: true)
    .snapshots()
    .map((event) {
        for (var document in event.docs) {
          messages.add(ChatMessage.fromMap(document.data()));
        }
    });
//print('LENGTH:'+messages.length.toString());
yield messages;}

Solution

You can use the following method.

  Stream<List<ChatMessage>> getForumChatStream(String forumId) async* {
    final firestore = FirebaseFirestore.instance;
    List<ChatMessage> messages = [];
    var docSnap = await firestore.collection('forums').doc(forumId).get();
    Forum forum = Forum.fromMap(docSnap.data()!);
    final result = firestore
        .collection('openMessages')
        .where('messageId', whereIn: forum.messageIds)
        .orderBy('timeSent', descending: true)
        .snapshots();
    await for (final r in result) {
      final docs = r.docs;
      for (final document in docs) {
        messages.add(ChatMessage.fromMap(document.data()));
        yield messages;
      }
    }
  }

Answered By – Sparko Sol

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *