Firebase Akışını Flutter'daki başka bir Akış için giriş olarak mı kullanıyorsunuz?

Dec 31 2020

Bağlam: Doğru çalışan iki Firebase Akışım var ve i) bir kullanıcı profili listesi ('kullanıcılar' koleksiyonu) ve ii) her bir kullanıcı profiline ait konumların bir listesini ('konumlar' koleksiyonu) ve daha sonra bunları özel bir Kullanıcı ve Konum modeliyle eşleyin.

Kullanıcı akışı:

class DatabaseService {

final String uid;
final String friendUid;
final String locationId;
DatabaseService({ this.uid, this.locationId, this.friendUid });

// collection reference for users
final CollectionReference userCollection = FirebaseFirestore.instance.collection('users');

// get users stream
Stream<List<CustomUserModel>> get users {

final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;

List<CustomUserModel> userList = [];

List<CustomUserModel> _streamMapper(DocumentSnapshot snapshot) {
  CustomUserModel individualUser = CustomUserModel(
    uid: snapshot.id,
    name: snapshot.data()['name'],
    username: snapshot.data()['username'],
    email: snapshot.data()['email'],
  );
  userList.add(individualUser);
  return userList;
}

  return userCollection.doc(uid).snapshots().map(_streamMapper);
}

ve Konum Akışı:

  // collection reference for location
   final CollectionReference locationCollection = 
   FirebaseFirestore.instance.collection('locations');

  Stream<List<Location>> get locations {

  final FirebaseAuth auth = FirebaseAuth.instance;
  final User user = auth.currentUser;
  final uid = user.uid;

  List<Location> _locationListFromSnapshot(QuerySnapshot snapshot) {
   List<Location> locationList = [];
    snapshot.docs.forEach((element) {
     Location individualLocation = Location(
       locationId: element.id,
       locationName: element.data()['locationName'],
       city: element.data()['city'],
     );
    locationList.add(individualLocation);
  });
   return locationList;
 }

  return userLocationCollection.doc(uid).collection('locations').snapshots()
   .map(_locationListFromSnapshot);
 }

Yapmak istediğim şey, tüm kullanıcılar için tüm konumları çıkaran özel bir Akış oluşturmaktır - başka bir deyişle, kullanıcı akışını konum akışı için bir girdi olarak kullanmak.

Burada hangi yaklaşımın işe yaradığından emin değilim - kullanıcı akışını konum akışına bir girdi parametresi olarak eklemeyi ve ardından bir döngü oluşturmayı düşündüm, bunun gibi bir şey:

Stream<List<Location>> allLocations(Stream<List<CustomUserModel>> users) {

final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;

List<Location> locationList = [];

users.forEach((element) {

// append user's locations to empty list
locationList.add(locationCollection.doc(element.first.uid).collection('locations')
.snapshots().map(SOME FUNCTION TO MAP A DOCUMENT SNAPSHOT TO THE CUSTOM LOCATION MODEL)

}

return locationList;

ama tabii ki bu bir akış değil, bir liste döndürdüğü için bir hata alıyorum. O yüzden nasıl ilerleyeceğimi bilmiyorum ...

Yanıtlar

4 dshukertjr Dec 31 2020 at 07:52

Acını duyuyorum. Oradaydım. Çok yakındın. Nasıl yapmayı sevdiğimi açıklayayım.

Her şeyden önce, biraz temizlik:

Bunları allLocationsişlevlerde kullanmıyormuşsunuz gibi görünüyordu , bu yüzden onları sildim

final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;

İkinci olarak, gelen işlevin dönüş türü değişmiş Stream<List<Location>>için Stream<Map<String, List<Location>>haritanın anahtar userId olacağı yerdir. Bu türü yararlı buluyorum çünkü kullanıcıların akışla senkronize olma sırası konusunda endişelenmenize gerek yok.

Üçüncüsü, akış oluştururken geri dönemezsiniz, ancak bir işlevden vazgeçmeniz gerekir. Ayrıca işlevi de işaretlemeniz gerekir async*(* bir yazım hatası değildir).

Bununla, allLocationsişleviniz için şuna benzer bir şey kullanmanızı öneriyorum :

class DataService {
  List<Location> convertToLocations(QuerySnapshot snap) {
    // This is the function to convert QuerySnapshot into List<Location>
    return [Location()];
  }

  Stream<Map<String, List<Location>>> allLocations(
      Stream<List<CustomUserModel>> usersStream) async* {
    Map<String, List<Location>> locationsMap = {};

    await for (List<CustomUserModel> users in usersStream) {
      for (CustomUserModel user in users) {
        final Stream<List<Location>> locationsStream = locationCollection
            .doc(user.uid)
            .collection('locations')
            .snapshots()
            .map(convertToLocations);
        await for (List<Location> locations in locationsStream) {
          locationsMap[user.uid] = locations;
          yield locationsMap;
        }
      }
    }
  }
}

Umarım bu yöntemi beğenirsiniz. Lütfen bir şey istediğiniz gibi değilse bana bildirin. Ayarlamalar yapabilirim.