![](/img/trans.png)
[英]How to do remove an entire document collection in angularfire firestore
[英]How to subscribe to an entire collection and a document within it simultaneously without duplicating the amount of reads?
我正在為學習目的編寫一個帶有 Flutter 和 Firestore 的跨平台待辦事項應用程序。 目前,我有以下設計,我想知道是否有更好的選擇。
該應用程序的主屏幕之一顯示所有任務的列表。 它通過訂閱相應的 Firestore 集合來執行此操作,為簡單起見,我們將其稱為/tasks
。
FirebaseFirestore.instance.collection("tasks").snapshots()
任務列表視圖中的每個磁貼都可以單擊。 單擊一個磁貼會打開一個新屏幕(帶有Navigator.push
),顯示有關該特定任務的詳細信息。
重要的是,這個屏幕也需要實時更新,所以僅僅從主屏幕傳遞(本地,不可變的)任務 object 是不夠的。 相反,此屏幕會訂閱與該任務對應的單個 Firestore 文檔。
FirebaseFirestore.instance.collection("tasks").doc(taskId).snapshots()
這在邏輯上對我來說是有意義的:詳細信息頁面只需要知道那個特定的文檔,所以它只訂閱它以避免接收不必要的更新。
問題是因為在詳細信息屏幕打開時,主屏幕的集合范圍訂閱仍然存在,如果文檔/tasks/{taskId}
更新,兩個偵聽器都會觸發。 根據這個、 這個和這個問題中的答案,這意味着我將對對該文檔的任何一次更新的兩次(重復)讀取收費。
此外,每個任務都可以有子任務。 這在 Firestore 中反映為每個任務的tasks
子集合。 例如,嵌套任務的路徑可能是: /tasks/abc123/tasks/efg875/tasks/aay789
。 通過對"tasks"
使用集合組查詢,主頁可以顯示所有任務,而不管嵌套。 上述詳情頁面還通過監聽子集合來顯示任務的子任務。 這允許對子任務進行復雜的查詢(過濾、排序等),但同樣的缺點是每次更新子任務都會重復讀取。
我想到的替代設計是:
僅在整個應用程序范圍內訂閱整個任務集(無論是平面集合還是集合組查詢),並在客戶端上進行任何和所有選擇、過濾等。 例如,任務的詳細信息頁面每次都會使用相同的集合范圍訂閱和 select 集合之外的適當任務。 任務/子任務的任何過濾和排序都將在客戶端完成。
打開詳情頁取消全館訂閱,返回主界面重新開啟。 這意味着當詳細信息頁面打開時,只會收到對該特定任務的更新,而不會被復制為兩次讀取。
這些設計中的任何一個看起來是最好的嗎? 我還缺少其他更好的選擇嗎?
在你的應用程序中創建一個TaskService
或類似的東西來處理監聽FirebaseFirestore.instance.collection("tasks").snapshots()
調用,然后在你的應用程序中,訂閱該服務的更新而不是 Firebase 本身(你可以創建兩個Stream
對象,一個用於全局更新,一個用於特定更新)。
然后,您的 Firebase 集合中只有一個正在閱讀。 一切都在應用程序端處理。
偽代碼:
class TaskService {
final List<Task> _tasks = [];
final StreamController<List<Task>> _signalOnTasks = StreamController.broadcast();
final StreamController<Task> _signalOnTask = StreamController.broadcast();
get List<Task> allTasks => _tasks;
Stream<List<Task>> get onTasks => _signalOnTasks.stream;
Stream<List<Task>> get onTask => _signalOnTask.stream;
void init() {
FirebaseFirestore.instance.collection("tasks").snapshots().listen(_onData);
}
void _onData(snapshot) {
/// get/update our tasks (maybe check for duplicates or whatever)
_tasks.addAll(snapshot.documents);
/// dispatch our signal streams
_signalOnTasks.add(snapshot.documents);
for(final task in snapshot.documents) {
_signalOnTask.add(task);
}
}
}
您可以讓TaskService
和InheritedWidget
在任何地方訪問它(或使用提供程序包),將您的偵聽器添加到您感興趣的任何 stream。您只需要將您的偵聽器簽入onTask
,這是正確的任務在對它做任何事情之前。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.