![](/img/trans.png)
[英]How to limit the access of a collectionGroup query to a specific document?
[英]How to limit collectionGroup query results to an ancestor?
我一直在閱讀博客文章https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html以更好地理解 collectionGroup 查詢。
雖然,我仍然有一個問題:如何將結果限制為特定的祖先。 讓我自己解釋一下。
想象一下,我有companies
生產有tyres
的cars
。 我們有不同品牌的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( {....})
}
});
});
通過交替使用DocumentReference
和CollectionReference
的parent
屬性。
但是,如果您有很多餐館,這可能不是最有效且經濟實惠的方式,因為您的 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.