在 Dart 中合并 Firestore 的单独查询流
Merge Firestore's separate queries Streams in Dart
我正在 Flutter 中实现 Todo 应用程序。我需要在客户端合并双重查询,以便在 Firestore 中执行 OR 请求。
一方面,我有以下执行双重查询的代码。
Future<Stream> combineStreams() async {
Stream stream1 = todoCollection
.where("owners", arrayContains: userId)
.snapshots()
.map((snapshot) {
return snapshot.documents
.map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc)))
.toList();
});
Stream stream2 = todoCollection
.where("contributors", arrayContains: userId)
.snapshots()
.map((snapshot) {
return snapshot.documents
.map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc)))
.toList();
});
return StreamZip(([stream1, stream2])).asBroadcastStream();
}
另一方面,我有以下代码将使用 Bloc 模式执行视图更新。
Stream<TodosState> _mapLoadTodosToState(LoadTodos event) async* {
_todosSubscription?.cancel();
var res = await _todosRepository.todos(event.userId);
_todosSubscription = res.listen(
(todos) {
dispatch(
TodosUpdated(todos));
},
);
}
我有以下错误。
flutter: Instance of '_AsBroadcastStream<List<List<Todo>>>'
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: type 'List<List<Todo>>' is not a subtype of type 'List<Todo>'
我尝试使用调试器查找更多信息,结果发现我的 StreamZip 源分别包含 2 个流。
目前我一次只能获得一个流。
我不知道如何继续才能获取 2 个流并显示它们。
你正在做一张地图的地图,其中 returns 一个列表的另一个列表。
您应该在创建订阅后压缩 QuerySnapshot
流并进行映射,然后您可以从中创建一个新的 Stream<List<Todo>>
。
///private method to zip QuerySnapshot streams
Stream<List<QuerySnapshot>> _combineStreams() async {
Stream stream1 = todoCollection
.where("owners", arrayContains: userId)
.snapshots()
});
Stream stream2 = todoCollection
.where("contributors", arrayContains: userId)
.snapshots()
});
return StreamZip(([stream1, stream2])).asBroadcastStream();
}
///exposed method to be consumed by repository
Stream<List<Todo>> todosStream() {
var controller = StreamController<List<Todo>>();
_combineStreams().listen((snapshots) {
List<DocumentSnapshot> documents;
snapshots.forEach((snapshot) {
documents.addAll(snapshot.documents);
});
final todos = documents.map((document) {
return Todo.fromEntity(TodoEntity.fromSnapshot(doc));
}).toList();
controller.add(todos);
});
return controller.stream;
}
我正在 Flutter 中实现 Todo 应用程序。我需要在客户端合并双重查询,以便在 Firestore 中执行 OR 请求。
一方面,我有以下执行双重查询的代码。
Future<Stream> combineStreams() async {
Stream stream1 = todoCollection
.where("owners", arrayContains: userId)
.snapshots()
.map((snapshot) {
return snapshot.documents
.map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc)))
.toList();
});
Stream stream2 = todoCollection
.where("contributors", arrayContains: userId)
.snapshots()
.map((snapshot) {
return snapshot.documents
.map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc)))
.toList();
});
return StreamZip(([stream1, stream2])).asBroadcastStream();
}
另一方面,我有以下代码将使用 Bloc 模式执行视图更新。
Stream<TodosState> _mapLoadTodosToState(LoadTodos event) async* {
_todosSubscription?.cancel();
var res = await _todosRepository.todos(event.userId);
_todosSubscription = res.listen(
(todos) {
dispatch(
TodosUpdated(todos));
},
);
}
我有以下错误。
flutter: Instance of '_AsBroadcastStream<List<List<Todo>>>'
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: type 'List<List<Todo>>' is not a subtype of type 'List<Todo>'
我尝试使用调试器查找更多信息,结果发现我的 StreamZip 源分别包含 2 个流。
目前我一次只能获得一个流。
我不知道如何继续才能获取 2 个流并显示它们。
你正在做一张地图的地图,其中 returns 一个列表的另一个列表。
您应该在创建订阅后压缩 QuerySnapshot
流并进行映射,然后您可以从中创建一个新的 Stream<List<Todo>>
。
///private method to zip QuerySnapshot streams
Stream<List<QuerySnapshot>> _combineStreams() async {
Stream stream1 = todoCollection
.where("owners", arrayContains: userId)
.snapshots()
});
Stream stream2 = todoCollection
.where("contributors", arrayContains: userId)
.snapshots()
});
return StreamZip(([stream1, stream2])).asBroadcastStream();
}
///exposed method to be consumed by repository
Stream<List<Todo>> todosStream() {
var controller = StreamController<List<Todo>>();
_combineStreams().listen((snapshots) {
List<DocumentSnapshot> documents;
snapshots.forEach((snapshot) {
documents.addAll(snapshot.documents);
});
final todos = documents.map((document) {
return Todo.fromEntity(TodoEntity.fromSnapshot(doc));
}).toList();
controller.add(todos);
});
return controller.stream;
}