Flutter Firestore 实时分页使用多个监听流合并

Flutter Firestore real-time pagination using multiple listeners streamed combined

我想使用 Bloc 从 Firestore 数据库创建分页屏幕。屏幕应随文档更改而更新。

我的 FirestoreProviderApi 收到来自 Bloc 单元的提取请求。从 Firestore 获取文档后,它使用 Stream.

将它们发送回 Bloc

FirestoreProviderApi:

  final _pollOverviewStreamController = BehaviorSubject<QuerySnapshot>();

  @override
  Stream<QuerySnapshot> getOverviewPolls<QuerySnapshot>() =>
      _pollOverviewStreamController.asBroadcastStream().cast();

  @override
  Future<void> fetchFirstOverviewPolls() async {
    _overviewPollsRef.limit(5).snapshots().listen((querySnapshot) {
      _pollOverviewStreamController.add(querySnapshot);
    });
  }

  @override
  Future<void> fetchNextOverviewPolls() async {
    if (_pollOverviewStreamController.value.docs.isEmpty) return;

    final lastDoc = _pollOverviewStreamController.value.docs.last;
    _overviewPollsRef
        .startAfterDocument(lastDoc)
        .limit(5)
        .snapshots()
        .listen((querySnapshot) {
      _pollOverviewStreamController.add(querySnapshot);
    });
  }

关于文档更改,我想更新我的文档列表

现在,每当发生更改时,都会将新的 QuerySnapshot 附加到流中(而不是替换旧的)。 有没有办法将多个侦听器组合到同一个流中,只聚合最新的数据?

问题已解决。

我找到了关于如何实施的很好的文档real-time pagination using Firestore(已经实施了,效果很好)。

Youtube 实施:Flutter and Firestore real-time Pagination.

High-level 步数:

  1. 创建一个class-scoped文档列表状态变量。
  2. 每次都流式传输整个列表
  3. 监听并迭代快照更改,update/add 文档到主列表
  4. 如果列表不为空,则从列表中的最后一个 文档中获取。

我的实现:

final List<DocumentSnapshot> _overviewPolls = [];

@override
  Future<void> fetchOverviewPolls(
      [int firstFetchLimit = 1, int nextFetchLimit = 1]) async {

    Query overviewPollsQuery = _overviewPollsRef.limit(firstFetchLimit);

    if (_overviewPolls.isNotEmpty) {
      overviewPollsQuery = overviewPollsQuery
          .startAfterDocument(_overviewPolls.last)
          .limit(nextFetchLimit);
    }

    overviewPollsQuery.snapshots().listen((querySnapshot) {
      if (querySnapshot.docs.isNotEmpty) {
        for (final doc in querySnapshot.docs) {
          int index = _overviewPolls.indexWhere((d) => d.id == doc.id);
          // if already exists - update poll
          if (index >= 0) {
            _overviewPolls[index] = doc;
          }
          // if new document - add poll
          else {
            _overviewPolls.add(doc);
          }
        }

        _pollOverviewStreamController.add(_overviewPolls);
      }
    });
  }

使用 orderBy

请注意,如果您在查询快照时使用 orderBy,对订单字段的任何更新 都会导致整个列表重新排序 个项目。此外,在某些情况下,它会自动获取更多项目(因为我们对每个快照使用限制,并且项目列表重新排序,一些快照可能需要获取更多项目以填补其限制)。