我一直在阅读博客文章https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html,以更好地了解collectionGroup查询。
尽管如此,我仍然有一个问题:如何将结果限制为特定的祖先。让我解释一下自己。
想象一下,我有companies
制造的cars
有tyres
。我们在不同的tyres
中使用了不同的cars
品牌。最后,我们建立了多对多关系。我知道我不应该在NoSQL世界中使用这个术语,但是我把狗称为狗:-)
无论如何,我的问题是:如果某个特定company
品牌(例如米其林)的tyre
A短缺,则需要标记此tyre
缺货。我想运行一个collectionGroup查询,例如:
db.collectionQuery("tyre")
.where("brand", "==", "Michelin")
.get()
.then(function (querySnapshot) {
// update flag accordingly
})
但这会更新其他companies
的库存。
我的问题是:您如何缩小collectionGroup查询结果,以便仅更新公司A的tyres
信息?
我可以将公司A docRef
包含在tyres
集合中,并使用where()
来缩小结果范围。这似乎是一种有效的方法。虽然,这是顶级集合和子集合之间的混合。这是最佳做法吗?
更新
实际上,我是按照餐馆的例子来介绍如何使用Firebase / firestore。餐厅可以有多个菜单。菜单可以包含多个项目。项目可以重复使用,因此可以显示在多个菜单中。
collection('restaurants').doc(..).collection('menus').doc(..).collection('items')
我想这是构造数据的最佳方法(相对于项目的顶级集合)。但是,可以在多家餐厅的多个菜单中轻松找到诸如Coffee之类的项目。如果一家餐厅缺咖啡,我该如何使用以下方法更新该特定餐厅的咖啡项目:
db.collectionQuery("items")
.where("name", "==", "Coffee")
.get()
.then(function (querySnapshot) {
// set available = false
})
答案 0 :(得分:2)
如果一家餐厅缺咖啡,我该如何更新咖啡 该特定餐厅的食物?
通过使用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( {....})
}
});
});
通过交替使用parent
和DocumentReference
的{{1}}属性。
但是,如果您有很多餐厅,这可能不是最有效和负担得起的方法,因为您的collectionGroup查询将返回很多记录。
一种更有效的方法是保留一组counters并通过Firestore监听器或Cloud Functions观看它们。
最后,请注意一个重要的点:您写到“一个菜单可以包含多个项目。项目可以重复使用,因此可以出现在多个菜单中”。请注意,CollectionReference
个文档位于
items
和
collection('restaurants').doc('r1').collection('menus').doc('m1').collection('items')
是完全不同的文档。这与SQL世界不同,在SQL世界中,一个表中的不同记录可以指向另一张表的相同记录。
结论:每个collection('restaurants').doc('r1').collection('menus').doc('m2').collection('items')
您最应该有一个itemsStock
集合,并且每次其中一个项目被“消耗/订购”时,都可以使用FieldValue.increment(-1)
来减少其数量。 / p>
换句话说,我建议将构成菜单的项目集合与保存项目计数器的项目集合分开(即restaurant
集合)。第一个专用于菜单项的选择,第二个专用于管理餐厅的库存。当来宾/顾客选择/订购商品时,您只会减少包含商品计数器的集合。
如果您要更新餐厅所有菜单中的所有“千层面”项(例如,添加食材,正如您在评论中提到的那样),那么一种非常普遍的方法确实是修改所有相应文档(在NoSQL世界中,这称为数据复制。
您将在我的答案的顶部使用确切的代码:您查询餐厅所有菜单中的所有“千层面”项目文档并进行更新。您可以通过Cloud Function触发此过程,该功能将“监视”您具有参考项目的主集合:每次更改该集合的文档(即一个项目)时,您都会更新菜单中的所有相似/对应项目doc子集合。
答案 1 :(得分:0)
我可以将A公司docRef包含在轮胎集合中,并使用where()缩小结果范围。这似乎是一种有效的方法。虽然,这是顶级集合和子集合之间的混合。这是最佳做法吗?
这是一种常用方法,因为在收集组查询中过滤文档的唯一方法是使用文档的字段。您不能将文档路径中的任何内容用作过滤器。为了方便查询,通常会在NoSQL类型数据库中复制数据。
但是,如果您想将查询限制为仅子集合,则可能不想拥有与子集合同名的顶级集合。