【问题标题】:How to only subscribe to firebase collection changes如何仅订阅 Firebase 集合更改
【发布时间】:2019-02-20 03:20:44
【问题描述】:

我在 Angular 应用程序中通过 @angular/fire 使用 firebase javascript sdk。

使用 angularfire Collection#stateChanges(),我以为我只是订阅一个集合的状态更改(基于描述)。 IE。在初始订阅时不会返回任何内容。但是,我发现 stateChanges() 会立即返回集合中的所有内容,然后再继续返回状态更改。

有没有办法订阅未来的状态变化,而不是“重播”过去的变化(直接使用firebase-js-sdk 或通过@angular/fire)?

例如,如果您已经下载了集合当前状态的副本,则在简单地订阅集合更新时,您不希望重新下载集合状态。

感谢您的帮助!

【问题讨论】:

    标签: angular firebase google-cloud-firestore angularfire2


    【解决方案1】:

    目前,firebase 不支持订阅查询更改。当您订阅查询时,您还必须立即下载所有相关文档(请参阅 firebase-js-sdk 存储库中的 issue #1551)。

    话虽如此,正如该问题中所指出的,您可以通过向您的文档添加updatedAt 属性并查询包含updatedAt > now 的所有文档来伪造此功能。这将使您订阅未来的更改。

    此解决方法的一个限制是 Firestore 仅支持在查询中的单个字段上使用不等式过滤器(>=< 等),因此在 updatedAt 字段上使用不等式过滤器可能有问题。

    【讨论】:

      【解决方案2】:

      您可能正在寻找的是集合上的stateChanges 方法。 来自文档:

      你为什么要使用它? - 上述方法返回一个按查询顺序排序的同步数组。 stateChanges() 在更改发生时发出更改,而不是同步查询顺序。这适用于 ngrx 集成,因为您可以在 reducer 方法中构建自己的数据结构。

      还有一个使用@angular/fire的代码示例:

      this.angularFirestore
        .collection('my-collection')
        .stateChanges(['added', 'removed', updated']) // double check the state change references, these were assumed
        .pipe(...);
      

      【讨论】:

      • 感谢您的热情,但正如我在问题中突出指出的那样,stateChanges() 在初始订阅时返回所有内容(然后在发生更改时返回对象)。我同意@angular/fire 文档对stateChanges() 的描述非常具有误导性。
      • 哎呀,你说得对,我确实有点过分了。但是,该方法是我能够实现类似功能的唯一方法。我可以想象您可能希望如何避免额外的读取。在您的问题中,您声明如果您已经下载了该集合,则不想重新下载。通常我认为这种功能会在单例中,您能否在有关您如何使用它的问题中分享更多信息?
      • 我又进入了 firebase-js-sdk 一些,但看起来我无法做我想做的事情。我创建了一个feature request in the sdk repo,它更详细地介绍了可能的用例。问题似乎是,目前,QuerySnapshot#docChanges 在第一次调用时返回整个查询。似乎没有关闭此功能的选项。
      【解决方案3】:

      以下方法是我用于类似案例的方法。 我有用户、组和组中用户的请求。

      登录时,我得到所需的数据(所有数据一目了然)。

      但是对于已登录的用户,我需要订阅该组请求的任何插入、删除或编辑(不仅仅是更新-at..)。

      所以我创建了一个更改请求的集合。 (groupRequestsChanged)

      我已经订阅了

      collection('groupRequestsChanged').doc(group-id-here...).valueChanged().subscribe()
      

      这种方法在某些情况下很有用。

      【讨论】:

        【解决方案4】:

        我参加这个聚会迟到了,但我通过首先获取我想要显示的尽可能多的文档(分页)来处理这个问题,然后使用stateChanges 订阅更改。所以首先我会做类似的事情

        public displayedMessages: Array<any>;
        this.db.collection('messages').ref.limitToLast(100).get().then(result => {
          // display the result, 
          this.displayedMessages = result;
        
          //then watch changes:
          this.db.collection('messages').stateChanges().pipe(
            skip(1),
            map(changes => {
              changes.forEach(itemDoc => {
                if (itemDoc.type == 'added') {
                  this.displayedMessages.push(item);
                } else if (itemDoc.type == 'modified') {
                  // find the message in displayedMessages and update the data
                } else if (itemDoc.type == 'removed') {
                  // find the index and splice it. 
                }
              })
            })
          )
        })
        

        这里的关键是来自 rxjs 的skip(1)。它会跳过第一个发出的值,即整个集合。你刚刚得到了get 的全部内容,所以你不需要stateChanges 的第一次发射。因此,现在每次更改该集合时,您只会得到更改。 ?

        【讨论】:

        • 这是个好建议。虽然我也应该在我的问题中提到成本是一个问题。我只想进行更改的原因之一是避免最初获取整个集合的成本(性能和金钱)。出于这个原因,skip(1) 对我来说不是一个好选择,但也许对其他人来说会是一个好选择。
        猜你喜欢
        • 1970-01-01
        • 2021-10-16
        • 1970-01-01
        • 2016-11-25
        • 1970-01-01
        • 1970-01-01
        • 2021-01-14
        • 1970-01-01
        • 2020-02-11
        相关资源
        最近更新 更多