如何在firebase firestore中准确合并多个流

Posted

技术标签:

【中文标题】如何在firebase firestore中准确合并多个流【英文标题】:How exactly to merge multiple streams in firebase firestore 【发布时间】:2020-12-09 13:51:04 【问题描述】:

在你说这是一个重复的问题或者我应该使用嵌套流构建器之前,请听我说完。

我正在设计一个社交媒体类型的应用程序。我希望用户在他们关注的人在他们的“我的关注者帖子”集合中发布内容时收到更新。 在应用程序中,应用程序将检查当前用户的关注列表(他关注的人)的 firebase rtdb 并列出他们的 uid。

我计划使用所述列表创建一个流列表(当然是按时间排序)并将它们合并到一个流中,然后将其馈送到私人提要页面上的流构建器中。

在此页面上,用户将能够轻松地关注他们感兴趣的人发布的内容。

我认为这样的系统比在“私人 Feed”集合中拥有文档的每个用户更具成本效益,每当有人发布内容时,该应用程序都会读取他们的关注者列表,然后及时在每个用户中发布更新他们的私人供稿之一。 因为... 想象一下拥有 200 万粉丝的人。即刻有 200 万次写入。后来,200 万次阅读。 我认为发帖者只需将帖子放在他们的“publicFeed”中,而不同的追随者只需收听该提要并与他们保持密切联系,就会更具成本效益。

但是.. 这需要实现多个流的合并(超过 2 个)。我该怎么做?

我尝试过阅读 RxDart,但对我来说它完全是希腊语。我是飞镖的初学者。我现在只写了大约 5 个月的代码。

【问题讨论】:

【参考方案1】:

您可以使用 async 包中的 StreamGroup:https://pub.dev/documentation/async/latest/async/StreamGroup-class.html 对来自多个流的事件进行分组 - 它由 dart 团队进行了详细记录和维护。如果您没有 RxDart 经验,这是一个不错的选择。它没有 rx 的所有功能,但对于初学者来说应该更容易理解它

【讨论】:

你能给我一个简单的例子来说明如何做到这一点。我完全是通过 youtube 教程学习的,所以,我还不擅长解码文档的编写方式。我从例子中学习得更好。假设您在新的 Cars 集合中有数据,在 newClothesCollection 中有一些其他数据,在 newKeyBoards 集合中有一些其他数据。您能否编写一些演示代码,说明如何使用 async 合并这三个并将它们提供给流构建器? 我已经设法使用它合并流,它确实有效。但是,关于在流构建器中显示合并的流,我面临一个全新的、完全不同的问题。不过,我将把它作为一个新问题发布。谢谢。【参考方案2】:

我最近有一个类似的案例,我建议你做的是这个 (我正在使用 Cloud Firestore,但我确定您已经编写了流,所以重要的部分是多个流的使用):

您必须将此插件添加到 pub spec.yaml: https://pub.dev/packages/rxdart

这里是(在您的帖子中,比如说 newPosts、oldPosts)的存储库:

class PostRepository 

  static CollectionReference get collection => yourCollectionRef;
    
  static Stream<List<Post>> newPosts() 
    Query query = collection
        .where('Your condition like was viewed', isEqualTo: false)
        .orderBy('updateDate', descending: true)
        .limit(50);
    return query.snapshots().map<List<Post>>((querySnapshot) 
      final _newPosts = querySnapshot.documents.map((doc) 
        final post = Post.fromDoc(doc);
        return post;
      ).where((p) => p != null);

      return _newPosts
    );
  

  static Stream<List<Post>> oldPosts() 
    Query query = collection
        .where('Your condition like was viewed', isEqualTo: true)
        .orderBy('updateDate', descending: true)
        .limit(50);
    return query.snapshots().map<List<Post>>((querySnapshot) 
      final _oldPosts = querySnapshot.documents.map((doc) 
        final post = Post.fromDoc(doc);
        return post;
      ).where((p) => p != null);

      return _oldPosts
    );
  

然后要获得多个流(上面的两个流结合在一起),请在您的小部件类中执行以下操作:

重要!你必须导入这个 - import 'package:rxdart/streams.dart';

List<Post> newPosts;
List<Post> oldPosts;

Widget _pageContent() 
  return SingleChildScrollView(
    child: Column(
      children: [
        ListView.builder(
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          itemCount: newPosts.length,
          itemBuilder: (context, index) 
            return ListTile(
              title: Text(newPosts[index].title)
            );
          
        ),
        ListView.builder(
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          itemCount: oldPosts.length,
          itemBuilder: (context, index) 
            return ListTile(
              title: Text(oldPosts[index].title)
            );
          
        )
      ]
    )
  );


Widget _posts() 
  return StreamBuilder(
    stream: CombineLatestStream.list([
      PostRepository.getNewPosts(),
      PostRepository.getOldPosts()
    ]),
    builder: (context, snap) 
     if (snap.hasError) 

        debugPrint('$snap.error');
        return ErrorContent(snap.error);

       else if (!snap.hasData) 

        return Center(
          child: CircularProgressIndicator(),
        );

      

      newPosts = snap.data[0];
      oldPosts = snap.data[1];

      return _pageContent();
    
  );

我的代码是从头开始写的,所以可能会有一些小错误,但我希望你明白这一点,享受:)

【讨论】:

非常感谢。虽然我认为不可能将列表视图放在滚动视图中。我以前做过,它给出了一些错误,比如“你不能把一个可滚动的东西放在另一个可滚动的虚拟对象中”。不过,我将尝试您的解决方案,然后给您反馈。 好的。如果您像示例中那样使用 shrinkwrap 和 neverscrollablescrollphysics,那么您的 2 个列表应该完全符合您的要求:) 非常感谢。我设法使用流组合并流,但我目前面临在流构建器中显示此合并流的新问题。但我将它作为一个全新的问题发布。谢谢你。 请注意,如果您想合并集合流(Stream> 而不是 Stream,您需要使用自定义合并器函数 - 在此示例中,他调用 CombineLatestStream.list它使用了一个对 Stream 有好处的默认组合器。在我的情况下,我无法让它工作,直到我意识到使用 Stream> 时你需要提供一个自定义组合器来处理它(获取一个 List> 然后根据需要将其展平以获得一个 Stream>)。所以你需要使用常规的CombineLatestStream(streamList, combinerFunc)

以上是关于如何在firebase firestore中准确合并多个流的主要内容,如果未能解决你的问题,请参考以下文章

Firebase Firestore 子集合

如何使用 Firebase Firestore 获取子集合? [复制]

如何遍历 Firestore(React 和 Firebase Web 应用程序)中的多个用户子集合?

如何将子集合添加到 Firebase Cloud Firestore 中的文档

如何在firebase firestore中准确合并多个流

新的 Firebase Firestore DocumentDb 如何为大型子集合建模