【问题标题】:Firestore: How can I re-order a collection I already have a reference to?Firestore:如何重新订购我已经参考的收藏?
【发布时间】:2018-09-06 14:24:36
【问题描述】:

有没有办法保留同一个集合的引用,但使用 firestore 更改排序?

TLDR: 这就像我想要实现的功能: https://stackoverflow.com/a/17320018, 但由于我的数据来自 Firestore,因此我还没有找到动态完成此任务的正确方法。


假设我有一个 messagesService.ts,其中包含消息集合和对消息 Observable 的引用:

messagesCollection: AngularFirestoreCollection<Message>
messages: Observable<Message[]>;

this.messagesCollection = this.db.collection('messages', ref => {
  return ref.orderBy('dateCreated', 'desc');
});

this.messages= this.messagesCollection.valueChanges();

当我将此数据弹出到 *ngFor="let message of messages | async" 时,它会按预期在顶部显示最新消息。

我需要帮助的地方:

我希望能够单击一个按钮并更改消息的顺序(或我从 firestore 获得的数据的顺序)。例如,您可以单击一个按钮以按最多喜欢或最高视图的消息或最旧的消息、字母顺序等进行排序。我是否需要为要对同一集合进行排序的每种方式提供单独的参考?这看起来很草率,有没有更干净的方法可以动态地做到这一点?

最初,我尝试过这样的事情:

sortMessagesBy(field) {
    this.messagesCollection = this.db.collection('messages', ref => {
          return ref.orderBy(field, 'desc');
    });
}

但是,这不起作用,因为它似乎更改了对集合的引用,因此可观察到的消息没有更新。

接下来,我尝试了这个:

sortMessagesBy(field) {
    this.messagesCollection = this.db.collection('messages', ref => {
          return ref.orderBy(field, 'desc');
    });
    this.messages= this.messagesCollection.valueChanges();
    return this.messages;
}

但这似乎创建了一个新的 this.messages 对象,这使得 ngFor 重新渲染整个页面并且看起来超级草率(即使使用 trackBy)。

最终,我想进一步缩小范围,在同一个集合中,我什至可能有一个 where 子句来定位特定的消息子集并能够应用相同的动态排序IE:

this.messagesCollection = this.db.collection('messages', ref => {
      return ref.where("type", "==", "todo").orderBy(field, 'desc');
});

如果不弄清楚如何动态地做到这一点,我只是不明白如何做到这一点。

【问题讨论】:

    标签: javascript angular firebase google-cloud-firestore angularfire2


    【解决方案1】:

    @Frank van Puffelen 的回答帮助我更好地理解了这一点,并且我能够想出类似的东西,这似乎可以解决这个问题:

    getMessages(type=null, field=null, direction=null) {
      console.log("sorting messages by: ", type, field, direction);
      this.messagesCollection = this.db.collection('messages', ref => {
        if (type && field) {
          return ref.where('typeId', '==', type).orderBy(field, direction? direction : 'desc');
        } else if (type && !field && !direction) {
          return ref.where('typeId', '==', type)
        } else if (!type && field) {
          return ref.orderBy(field, direction? direction : 'desc');
        } else {
          return ref;
        }
      });
      this.messages = this.messagesCollection.valueChanges();
      return this.messages;
    }
    

    这使我不必为我想要的每个查询在我的服务中保留一个不同的变量,这看起来像是一团糟。现在,在任何给定的组件中,我都可以这样调用:

    this.messages = this.messageService.getMessages(this.type, 'views');
    

    或者这个:

    this.messages = this.messageService.getMessages(null, 'dateCreated');
    

    注意:它确实需要我在 typeId 字段以及我计划排序的每个不同字段(视图、dateCreated、喜欢等)上创建复合索引,但 firebase 使这很漂亮容易。

    现在,我只需要弄清楚为什么当我调用这个函数时整个页面会闪烁,它会替换 *ngFor 中使用的 this.messages 中的值。即使我使用 trackBy,当我应用不同的排序时,它似乎也在重新渲染整个页面。

    更新:

    当我订阅组件中的消息(而不是使用 ngFor 中的 async 管道)时,它会按预期工作并且不会重新呈现整个页面。示例 MessageComponent.ts:

    this.messageService.getMessages(this.type).subscribe(res => this.messages = res);  
    

    【讨论】:

      【解决方案2】:

      据我所知,AngularFirestoreCollection class 是不可变的。这意味着您在构建后无法更改它。

      这与 Firebase SDK 类一致。这段代码

      ref.where("type", "==", "todo").orderBy(field, 'desc')
      

      创建一个Query object,它也是不可变的。要更改结果的顺序,您必须创建一个新查询和一个新的AngularFirestoreCollection。

      【讨论】:

        猜你喜欢
        • 2020-09-19
        • 2014-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-31
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多