簡體   English   中英

Firestore 活動文檔快照偵聽器中斷排序

[英]Firestore active document snapshot listener breaks sorting

我遇到了一個firestore問題,希望有人可以幫助我。

我有一個活動的文檔快照偵聽器,它似乎正在破壞排序行為,我不知道為什么。

在我的組件的構造函數中,我初始化了一次文檔快照偵聽器:

this.listen = this.fs.collection('users').doc('0EwcWqMVp9j0PtNXFDyO').ref.onSnapshot(t => {
  console.log(t)
})

每當我單擊“排序”按鈕時,它都會初始化一個按名字排序的新集合查詢。

  async onSort() {
    if (this.first) {
      this.first();
    }

    this.sort = this.sort === 'asc'? 'desc' : 'asc';    
    alert(this.sort)
    let arr = []
    let lastDoc = null
    let queryRef = this.fs.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20);
    this.users$ = this._users$.asObservable()

    // initialize a blank list
    this._users$.next([])

    // subscribe to user list snapshot changes
    const users1: { users: any, last: any } = await new Promise((resolve, reject) => {
      this.first = queryRef.onSnapshot((doc) => {
        console.log("Current data: ", doc);
        
        const users = doc.docs.map(t => {
          return {
            id: t.id,
            ...t.data() as any
          }
        })
        console.log(users)
        resolve({
          users: users,
          last: doc.docs[doc.docs.length -1]
        })
      });
  
    })
    this._users$.next(this._users$.value.concat(users1.users))

  }

但是,這並沒有按預期工作。 排序返回一條記錄(應該有 20 條記錄,基於限制)。

在此處輸入圖像描述

有趣的是,取消訂閱文檔快照會修復排序問題。 正在返回 20 條記錄,並且排序行為正確。

在此處輸入圖像描述

有人可以解釋我做錯了什么嗎?

這是重現該問題的最小 Stackblitz。

問題演示

[編輯]

越來越接近解決方案和理解......感謝@ZackReam 的解釋以及@Robin 和@Zack 的規范答案。

似乎this._firestore.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20).onSnapshot(...)確實發出了兩次 - 一次用於活動文檔偵聽器(在緩存中有 1 條記錄),第二次用於排序的集合(不在緩存中,因為每次執行sortswitchMap都會取消訂閱)。

我們可以在 Zack 發布的功能演示中看到這一點——它閃爍着與文檔偵聽器相對應的一條記錄,然后片刻之后,列表中填充了排序后的集合。

你的聽眾越活躍,結果的閃現就越奇怪。 這是設計使然嗎? 對我來說似乎有缺陷......

直觀地說,我希望this._firestore.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20)查詢中的snapshotChanges()valueChanges()返回 20 個結果(排序后的前 20 個),獨立於任何其他文檔偵聽器。 這個查詢的第一個快照是來自文檔查詢的初始活動文檔,這與直覺相反——這應該與排序查詢無關。

我在一個簡化的環境中使用了您的示例數據,我想我知道發生了什么。 這是我的游樂場,只需更新AppModule以指向您的 Firebase 項目。

發生了什么?

當您調用onSort()時,您正在重新訂閱queryRef.onSnapshot 此回調觸發兩次:

  1. 訂閱后,它會立即觸發 Firestore 本地緩存中可用的一組初始數據(在您的情況下,它有一個記錄,我稍后會解釋)。
  2. 獲取實際數據后,它會使用您希望的完整數據集再次觸發。

在 Playground 中,確保已訂閱Document ,然后訂閱Sorted Collection 在控制台中,您會看到它兩次觸發:

在此處輸入圖像描述

不幸的是,由於您將此偵聽器包裝在 Promise中,因此您只會獲得第一次火災,因此只能獲得緩存中的單個記錄。

為什么取消訂閱文檔快照會修復它?

似乎本地緩存是根據當前打開的onSnapshot訂閱填充的。 因此,在您的情況下,您有一個偵聽器來監聽單個記錄的快照,因此這是您的緩存中唯一的東西。

在 Playground 中,嘗試使用各種訂閱狀態訪問Log Cache 例如,雖然只有Document Subscribed為 true,但緩存中只有一條記錄。 當兩個訂閱都處於活動狀態時,您會在緩存中看到大約 20 條記錄。

如果您取消訂閱所有內容並點擊Log Cache ,則緩存為空。

事實證明,如果在上面的步驟 1 中沒有數據可以從緩存中返回,它會完全跳過該步驟

在操場上,確保Document已取消訂閱,然后訂閱Sorted Collection 在控制台中,您會看到它只觸發一次:

在此處輸入圖像描述

這恰好適用於您的 Promise,因為第一次也是唯一一次觸發包含您希望的數據。

如何解決這個問題?

firebase-js-sdk庫中的此評論按預期描述了此行為,以及原因。

Promise 與.onSnapshot配對是擾亂數據流的主要因素,因為.onSnapshot預計會觸發不止一次。 你可以改用.get ,它在技術上可以工作。

然而,正如 Robin 指出的那樣,專注於利用@angular/fire功能的更具反應性的 RxJS 方法)將 go 走很長的路。

功能齊全的示例。

我找不到您的代碼的問題,因為您達到了 firebase 配額。 對我來說,您的排序似乎有點過於復雜並引入了賽車問題。 我認為您可以通過使用 RxJS 來降低復雜性。 像這樣的東西會起作用: https://stackblitz.com/edit/angular-ivy-cwthvf?file=src/app/app.component.ts

我無法真正測試它,因為您達到了配額。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM