Search code examples
firebasefluttergoogle-cloud-firestorestream-builderflutter-streambuilder

Flutter Firebase async query not retrieving data inside a stream function


I am trying to query a User from firebase within another query but for some reason but I can't get the code to work

The function the wont run is await usersRef.doc(uid).get(); and can be found here:

static getUserData(String uid) async {
    return await usersRef.doc(uid).get();
  }

  static  DirectMessageListModel getDocData(QueryDocumentSnapshot qdoc, String uid)  {
    Userdata postUser = Userdata.fromDoc(getUserData(uid));
    return DirectMessageListModel.fromDoc(qdoc, postUser);
  }

  static DirectMessageListModel fromDoc(QueryDocumentSnapshot doc, Userdata altUser) {
    return DirectMessageListModel(
      doc['chatId'],
      doc['lastMsgContent'],
        doc['lastMsgType'],
        altUser
    );
  }

parent function:

Stream<List<DirectMessageListModel>> getMeassageList(){
    var snaps = FirebaseFirestore.instance.collection('directMessages').where('users', arrayContains: userdata!.uid).snapshots();
    List<String> usersListElement = [];

    return snaps.map((event) { return event.docs.map((e) {
      usersListElement = [e.get('users')[0], e.get('users')[1]];
      usersListElement.remove(userdata!.uid);
      return DirectMessageListModel.getDocData(e, usersListElement.first);
    }).toList();
    });


  }

Solution

  • You forgot to wait for the future getUserData(uid) to complete.

    Try this:

    static Future<DocumentSnapshot<Object>> getUserData(String uid) async {
      return await usersRef.doc(uid).get();
    }
    
    static DirectMessageListModel getDocData(
      QueryDocumentSnapshot qdoc,
      String uid,
    ) async {
      Userdata postUser = Userdata.fromDoc(await getUserData(uid)); // await here
      return DirectMessageListModel.fromDoc(qdoc, postUser);
    }
    
    ..
    // parent function.
    // Also wait for the future in the parent function.
    
    // UPDATE BELOW! Define the parent function like this:
    Stream<List<Future<DirectMessageListModel>>> getMeassageList() {
      var snaps = FirebaseFirestore.instance
          .collection('directMessages')
          .where('users', arrayContains: userdata!.uid)
          .snapshots();
      List<String> usersListElement = [];
    
      return snaps.map((event) {
        return event.docs.map((e) async {
          usersListElement = [e.get('users')[0], e.get('users')[1]];
          usersListElement.remove(userdata!.uid);
          return await DirectMessageListModel.getDocData(e, usersListElement.first);
        }).toList();
      });
    }
    

    NB: You are fetching user data (either sender/receiver) for each message in directMessages collection. It might be better to store just sender/receiver name in directMessages collection and simply display that. Then if the user clicks on a message, you can then fetch the full sender/receiver data.