簡體   English   中英

如何將 collectionGroup 查詢結果限制為祖先?

[英]How to limit collectionGroup query results to an ancestor?

我一直在閱讀博客文章https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html以更好地理解 collectionGroup 查詢。

雖然,我仍然有一個問題:如何將結果限制為特定的祖先。 讓我自己解釋一下。

想象一下,我有companies生產有tyrescars 我們有不同品牌的tyres ,用於不同的cars 最后,我們有一個多對多的關系。 我知道我不應該在 NoSQL 世界中使用這個詞,但我稱狗為狗:-)

無論如何,我的問題如下:如果我們 A company的特定tyre品牌(比如米其林)出現短缺,您需要將該tyre標記為缺貨。 我想運行一個 collectionGroup 查詢,例如:

db.collectionQuery("tyre")
  .where("brand", "==", "Michelin")
  .get()
  .then(function (querySnapshot) {
    // update flag accordingly
  })

但這會更新其他companies的股票。

我的問題是:您將如何縮小 collectionGroup 查詢結果的范圍,以便只更新 A 公司的tyres信息?

我可以將公司 A docRef包含在tyres集合中,並使用where()來縮小結果范圍。 這似乎是一種有效的方法。 雖然,它將是頂級集合和子集合之間的混合。 這是最佳實踐嗎?

更新

實際上,我正在效仿餐廳的例子,將我的手放在火力基地/火力店上。 一家餐廳可以有多個菜單。 一個菜單可以有多個項目。 項目可以重復使用,因此出現在多個菜單中。

collection('restaurants').doc(..).collection('menus').doc(..).collection('items')

我喜歡認為這是構建數據的最佳方式(與項目的頂級集合相比)。 但是像咖啡這樣的東西很容易在多家餐廳的多個菜單中找到。 如果一家餐廳的咖啡短缺,我如何使用以下方式更新該特定餐廳的咖啡項目:

db.collectionQuery("items")
  .where("name", "==", "Coffee")
  .get()
  .then(function (querySnapshot) {
    // set available = false
  })

如果一家餐廳的咖啡短缺,我如何更新該特定餐廳的咖啡項目?

通過使用 collectionGroup 查詢,您可以這樣做:

  db.collectionQuery('items')
    .where('name', '==', 'Coffee')
    .get()
    .then(function (querySnapshot) {
      querySnapshot.forEach(function (doc) {
        const itemQuantity = doc.data().itemQuantity;
        if (itemQuantity === 0) {
          const restaurantRef = doc.ref.parent.parent.parent.parent;
          return restaurantRef.update( {....})
        }
      });
    });

通過交替使用DocumentReferenceCollectionReferenceparent屬性。


但是,如果您有很多餐館,這可能不是最有效且經濟實惠的方式,因為您的 collectionGroup 查詢將返回大量記錄。

一種更有效的方法是保留一組 計數器並通過 Firestore 偵聽器或 Cloud Functions 監視它們。


最后,請注意重要的一點:您編寫“一個菜單可以有多個項目。項目可以重復使用,因此存在於多個菜單中”。 請注意, items文件在

collection('restaurants').doc('r1').collection('menus').doc('m1').collection('items')

並且在

collection('restaurants').doc('r1').collection('menus').doc('m2').collection('items')

是完全不同的文件 這與 SQL 世界不同,其中一個表中的不同記錄可以指向另一個表的相同記錄。


結論:您很可能每restaurant都有一個itemsStock集合,並且每次“消費/訂購”其中一個項目時,您可以使用FieldValue.increment(-1)減少其數量。

換句話說,我建議將組成菜單的項目的 collections 與包含項目計數器的項目(即itemsStock集合)分開。 第一個專門用於菜單項選擇,第二個專門用於管理餐廳的庫存。 當客人/客戶選擇/訂購物品時,您只會減少持有物品櫃台的收藏。


根據您的評論更新:

如果您想更新餐廳所有菜單中的所有“千層面”項目(例如添加成分,正如您在評論中提到的),一個非常常見的方法確實是修改所有相應的文檔(這稱為NoSQL 世界中的數據重復)。

您將使用我答案頂部的確切代碼:您查詢餐廳所有菜單中的所有“烤寬面條”項目文檔並更新它們。 您可以通過 Cloud Function 觸發此過程,該 Cloud Function 將“監視”您具有參考項目的主集合:每次更改此集合的文檔(即項目)時,您都會更新菜單中的所有相似/對應項目文檔子集合。

我可以將公司 A docRef 包含在輪胎集合中,並使用 where() 來縮小結果范圍。 這似乎是一種有效的方法。 雖然,它將是頂級集合和子集合之間的混合。 這是最佳實踐嗎?

這是一種常見的方法,因為在集合組查詢中過濾文檔的唯一方法是使用文檔的字段。 您不能將文檔路徑中的任何內容用作過濾器。 NoSQL類型的數據庫為了方便查詢,經常會出現重復數據。

但是,如果要將查詢限制為子 collections,您可能不希望擁有與子 collections 同名的頂級集合。

暫無
暫無

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

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