[英]Using a Firebase Stream as an input for another Stream in Flutter?
上下文:我有兩個 Firebase 流可以正常工作,它們獲取 i) 用戶配置文件列表(“用戶”集合),以及 ii)屬於每個用戶配置文件的位置列表(“位置”集合),以及然后將 map 交給自定義用戶和位置 model。
用戶 stream:
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);
}
和位置 Stream:
// 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);
}
我想要做的是生成一個自定義 Stream,它輸出所有用戶的所有位置 - 換句話說,使用用戶 stream 作為位置 stream 的輸入。
我不確定這里使用哪種方法 - 我考慮將用戶 stream 作為輸入參數添加到位置 stream,然后創建一個 for 循環,如下所示:
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;
但當然我得到一個錯誤,因為它返回一個列表,而不是 stream。所以我不知道如何繼續......
我聽到你的痛苦。 我去過那里。 你非常接近。 讓我解釋一下我喜歡怎么做。
首先,一些清理:
好像你沒有在allLocations
函數中使用這些,所以我刪除了它們
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
其次,我將 function 的返回類型從Stream<List<Location>>
更改為Stream<Map<String, List<Location>>
,其中 map 的鍵將是 userId。 我發現這種類型很有用,因為您不必擔心用戶的順序與 stream 同步。
第三,當你創建流時,你不能返回,但必須從 function 中產生。你還必須將 function 標記為async*
(* 不是錯字)。
有了這個,我建議你為你的allLocations
function 使用這樣的東西:
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;
}
}
}
}
}
我希望你喜歡這個方法。 如果有什么不是您想要的,請告訴我。 我可以做出調整。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.