在Dart中合并Firestore的单独查询流

时间:2019-09-12 21:27:13

标签: asynchronous flutter dart stream future

我正在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个流并显示它们。

1 个答案:

答案 0 :(得分:2)

您正在制作地图的地图,该地图将返回另一个列表的列表。 创建订阅后,应压缩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;
}