Search code examples
flutterdartdart-asyncdart-stream

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


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;
          }
        }
      }
    

    Or

    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()!);
      yield* firestore
          .collection('openMessages')
          .where('messageId', whereIn: forum.messageIds)
          .orderBy('timeSend', descending: true)
          .snapshots()
          .map((event) =>
              event.docs.map((e) => ChatMessage.fromMap(e.data())).toList());
    }