Firestore:如何重新订购我已经引用的集合?

时间:2018-03-28 03:02:17

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

有没有办法保留同一个集合的引用,但是使用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');
});

我只是不知道如何在不弄清楚如何动态地做到这一点的情况下做到这一点。

2 个答案:

答案 0 :(得分:4)

据我所知,AngularFirestoreCollection class是不可变的。这意味着您可以在构建之后对其进行更改。

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

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

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

答案 1 :(得分:2)

@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字段上创建复合索引以及我计划按顺序排列的每个不同字段(views,dateCreated,likes等),但是firebase使它非常漂亮容易。

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

<强>更新

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

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