在 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;
}