Firestore:如何重新订购我已经参考过的系列? [英] Firestore: How can I re-order a collection I already have a reference to?
问题描述
有没有办法保留同一个集合的引用,但使用 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 字段以及我计划按顺序排序的每个不同字段(视图、日期创建、喜欢等)上创建复合索引,但是 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屋!