Firestore:如何重新排序已经引用的收藏集? [英] Firestore: How can I re-order a collection I already have a reference to?

查看:76
本文介绍了Firestore:如何重新排序已经引用的收藏集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以保留相同集合的引用,但可以使用firestore更改顺序?

TLDR::这就像我要实现的功能: https://stackoverflow.com/a/17320018 , 但是由于我的数据来自Firestore,所以我还没有完全找到动态完成此操作的正确方法.

TLDR: This is like the functionality I'm trying to achieve: https://stackoverflow.com/a/17320018, but since my data is from firestore, I haven't quite figured out the correct way to accomplish this dynamically.

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

Say I have a messagesService.ts which contains a collection of messages and a reference to an Observable of messages:

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"中时,它会按预期在顶部显示最新消息.

When I pop this data into an *ngFor="let message of messages | async" it displays the newest messages on top as expected.

需要帮助的地方

我希望能够单击一个按钮并更改消息的顺序(或从Firestore获取的数据的顺序).例如,您可以单击一个按钮来按喜欢或查看次数最高的消息排序,或按消息的最旧消息排序,字母排序的最早消息.对于要对同一集合进行排序的每种方式,我是否需要单独的参考?这似乎很草率,有没有更干净的方法可以动态地执行此操作?

I'd like to be able to click a button and change the ordering of the messages (or the ordering of the data I get from firestore). For example, you could click a button to sort by messages with the most likes, or highest views, or the oldest messages, alphabetical, etc. Do I need to have a separate reference for every single way I want to sort the same collection? That seems sloppy, is there a cleaner way to do this dynamically?

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

Initially, I tried something like this:

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

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

However, this didn't work because it seemed to change the reference to the collection, so the messages observable wasn't updated.

所以接下来,我尝试了这个:

So next, I tried this:

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时也是如此).

but this seems to create a new this.messages object which makes ngFor re-render the entire page and looks super sloppy (even when using trackBy).

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

Eventually, I'd like to narrow things down further, in the same collection where I may even have a where clause to target a specific subset of messages and be able to apply the same dynamic sorting too, I.E.:

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

而且我只是不知道如何动态地做到这一点而看不到.

and I just don't see how I could do this without figuring out how to do it dynamically.

推荐答案

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

@Frank van Puffelen's answer helped me understand this better, and I was able to come up with something like this, that seems to work for this problem:

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 prevents me from having to keep a different variable in my service for each query I'd want which seemed like it'd be a mess. Now, in any given component, I can make a call like this:

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

或者这个:

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

注意:确实需要我在typeId字段上创建组合索引,并计划按顺序(视图,dateCreated,点赞等)对每个不同的字段进行排序,但是firebase使其相当漂亮简单.

Of Note: It did require me to create composite indexes on the typeId field along with each distinct field I plan to order by (views, dateCreated, likes, etc), but firebase makes that pretty easy.

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

Now, I just have to figure out why the whole page flickers when I call this function and it replaces the value in this.messages which is used in an *ngFor. It appears like it's re-rendering the entire page when I apply a different ordering even when I use trackBy.

更新:

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

When I subscribe to the messages in the component (instead of using the async pipe in the ngFor) it works as expected and does not re-render the entire page. Example MessageComponent.ts:

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

这篇关于Firestore:如何重新排序已经引用的收藏集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆