firebase - 使用 Firebase 流作为 Flutter 中另一个流的输入?
问题描述
背景:我有两个正常工作的 Firebase 流,它们获取 i)用户配置文件列表(“用户”集合),以及 ii)属于每个用户配置文件的位置列表(“位置”集合),以及然后将它们映射到自定义用户和位置模型。
用户流:
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);
}
和位置流:
// 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);
}
我想要做的是生成一个自定义流,它为所有用户输出所有位置 - 换句话说,使用用户流作为位置流的输入。
我不确定什么方法在这里有效 - 我考虑将用户流作为输入参数添加到位置流,然后创建一个 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;
但当然我得到一个错误,因为它返回一个列表,而不是一个流。所以我不知道如何继续......
解决方案
我听到你的痛苦。我去过那里。你非常接近。让我解释一下我喜欢怎么做。
首先,进行一些清理:
好像你没有在allLocations
函数中使用这些,所以我删除了它们
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
其次,我将函数的返回类型从Stream<List<Location>>
mapStream<Map<String, List<Location>>
的键将是 userId 更改为。我发现这种类型很有用,因为您不必担心用户与流同步的顺序。
第三,当您创建流时,您不能返回,而必须从函数中屈服。您还必须标记函数async*
(* 不是错字)。
有了这个,我建议你为你的allLocations
功能使用这样的东西:
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;
}
}
}
}
}
我希望你喜欢这种方法。如果有什么不是你想要的,请告诉我。我可以做出调整。
推荐阅读
- vba - 无法使用 Outlook VBA 聚焦 Outlook 窗口并单击通讯簿
- c# - 我想防止使用 Asp.net 核心流式验证更新属于对象的 FirstName 和 LastName 属性
- python - Radial Axis plotly express显示浮点数而不是整数?
- sql-server - 有没有一种方便的方法来比较 SQL 中的每周数据?
- r - 为每一行数据填充一个矩阵的函数
- javascript - 选择 iframe 内的元素返回空数组
- java - Cassandra -f 找不到依赖库 java.lang.UnsatisfiedLinkError
- python - 搜索 json 文件返回数据框列中键的一部分
- bash - 如何在bash中忽略diff的输出
- r - 使用 R 中另一个数据框的值在数据框中创建一列