fluttergoogle-cloud-firestorefutureflutter-futurebuilderflutter-streambuilder

Make a stream wait for data to assign a late property


I have following code. I need to assign a late userName (not stored in database BID table) from the Bid Object that i retreive from the firestore with a stream. The userName can be found in another table in the database (USER table). I need to connect those 2 all while a streambuilder is building with BID object stream coming in.

Repository

  final _firestoreDB = FirebaseFirestore.instance;

  Future<String> getDbUserNameFromDbUserID({required String dbUserID}) async {
    try {
      final docUser = _firestoreDB.collection('users').doc(dbUserID);
      final snapshot = await docUser.get();

      if (snapshot.exists) {
        if (snapshot.data() != null){
          return DbUser.fromJson(snapshot.data()!).userName;
        }
      }
      throw Exception("getDBUserByDBUserId() No fireStore userName found");
    } catch (e) {
      throw Exception(e);
    }
  }


  Stream<List<Bid>> getAllBidsByItemId({required String itemID}) {
    try {
      return _firestoreDB
          .collection('bids')/*.orderBy('timestamp')*/
          .where('itemID', isEqualTo: itemID)
          .snapshots()
          .map((snapshot) =>
          snapshot.docs.map((doc) {
            Bid bid = Bid.fromJson(doc.data());
            bid.bidId = doc.id;
            **bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID); ///????**
            return bid;
          }).toList());
    } catch (e) {
      throw Exception(e);
    }
  }

model

class Bid {
  late String bidId;
  **late String userName;**
  final String bidderID;
  final String itemID;
  final double price;
  final DateTime timestamp;


  Bid(
      {
      required this.bidderID,
      required this.itemID,
      required this.price,
      required this.timestamp});

  Map<String, dynamic> toJson() => {
        'bidderID': bidderID,
        'itemID': itemID,
        'price': price,
        'timestamp': timestamp,
      };

  static Bid fromJson(Map<String, dynamic> json) => Bid(
        bidderID: json['bidderID'],
        itemID: json['itemID'],
        price: json['price'],
        timestamp: (json['timestamp'] as Timestamp).toDate(),
      );
}

How can I assign the late String userName when the stream gets the objects from the firestore?

Whats the best practice to do this? I assume this is not the best way to go about it?

I am using Bloc and Firestore Firebase

Thank you

SOLUTION

  Stream<List<Bid>> getAllBidsByItemId({required String itemID}) async* {
try {
  yield* _firestoreDB
      .collection('bids')
      .where('itemID', isEqualTo: itemID)
      .snapshots()
      .asyncMap<List<Bid>>((event) async {
    List<Bid> bids = [];

    for (var doc in event.docs) {
      try {
        Bid bid = Bid.fromJson(doc.data());
        bid.bidId = doc.id;
        bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID);

        bids.add(bid);
      } catch (e) {
        throw Exception(e);
      }
    }
    return bids;
  });
} catch (e) {
  throw Exception(e);
}

}

This worked for me


Solution

  • SOLUTION

    Stream<List<Bid>> getAllBidsByItemId({required String itemID}) async* {
    try {
      yield* _firestoreDB
      .collection('bids')
      .where('itemID', isEqualTo: itemID)
      .snapshots()
      .asyncMap<List<Bid>>((event) async {
    List<Bid> bids = [];
    
    for (var doc in event.docs) {
      try {
        Bid bid = Bid.fromJson(doc.data());
        bid.bidId = doc.id;
        bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID);
    
        bids.add(bid);
      } catch (e) {
        throw Exception(e);
      }
    }
    return bids;
      });
    } catch (e) {
      throw Exception(e);
    }}