我有一个firestore数据库,它将一些文档按ID存储在多个位置。我想写一个函数,可以通过ID访问该文档的所有实例,并更新/删除它们,而不知道它们到底在哪里。
例如,在一个购物示例中,有多个用户,每个用户都有一个子集合,其中包含购物车、心愿单和owned。文档ID可能存在也可能不存在于用户文档的每个子集合中。我正试图编写一个函数来遍历这些列表,并在匹配docID时执行操作,但一直未能找到这样的示例。
我知道如何将所有引用添加到一个批中,但不知道如何在不对整个用户集合进行大量读/写操作的情况下找到它们。这可能吗?
我最初的想法是:
let batch = admin.firestore().batch();
let allUsers = db.collection('users').get()
.then(snapshot => {
snapshot.forEach(doc => {
batch.delete(db.collection('users').doc(doc.id).collection('cart').doc(ID_TO_MATCH));
batch.delete(db.collection('users').doc(doc.id).collection('wishlist').doc(ID_TO_MATCH));
batch.delete(db.collection('users').doc(doc.id).collection('owned').doc(ID_TO_MATCH));
});
})
.catch(err => {
console.log('Error getting documents', err);
});
return batch.commit().then(function () {
// should delete all the direct referenes
});
这将起作用,因为firestore会成功删除未退出的文档。明显的缺点是随着用户数量的增长,文档读取量很大。是否可以使用.where()
查询来提高效率?
您可以使用基于documentId sentinel的where()
查询,如下所示:
...collection('cart').where(firebase.firestore.FieldPath.documentId(), '==', ID_TO_MATCH)
但我不认为它会在定价或性能方面有所改变。事实上,正如文档中所解释的,"即使查询没有返回结果,您执行的每个查询也要至少读取一个文档"。所以通过阅读文档
collection('cart').doc(ID_TO_MATCH)
或者通过
collection('cart').where(firebase.firestore.FieldPath.documentId(), '==', ID_TO_MATCH)
没有任何区别IMO.
另一种可能性是使用collectionGroup查询。在这种特定情况下,问题是当您通过FieldPath.documentId()
查询集合组时,提供的值必须导致有效的文档路径。有关更多详细信息,请参阅此SO帖子。因此,这将不适用于ID_TO_MATCH
。。。
但是有一个解决方法:您可以在文档中保存一个与文档ID具有相同值的字段,然后collectionGroup查询就可以工作了。
因此,在文档中有一个字段docId
,它包含文档ID的值,您可以编写以下查询:
const cartsQuery = db.collectionGroup('cart').where('docId', '==', ID_TO_MATCH);