如果我在集合中有大量文档,我是否可以获取文档数而无需加载整个集合。
db.collection('largecollection').get().then(snapshot => {
length = snapshot.size;
})
答案 0 :(得分:3)
没有内置API来获取集合中文档数量的计数。因此,默认情况下,您必须下载所有文档才能对其进行统计。
正如Renaud评论的那样,常见的解决方法是保留一个单独的计数器,每次添加/删除文档时都会更新。每次添加/删除文档时,您都可以在应用内updating the counter with a transaction执行此操作。但在服务器中执行此操作更为可靠,例如Cloud Functions for Firebase。有关此方法的示例,请参阅the functions-samples
repo。虽然该示例适用于Firebase实时数据库,但该方法同样适用于Firestore。
另请参阅distributed counters上的Firestore文档部分。
答案 1 :(得分:2)
请小心计算大型馆藏的文档数。如果您希望每个集合都有一个预先计算的计数器,那么对于Firestore数据库来说有点复杂。
在这种情况下,此类代码无效:
export const customerCounterListener =
functions.firestore.document('customers/{customerId}')
.onWrite((change, context) => {
// on create
if (!change.before.exists && change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count + 1
}))
// on delete
} else if (change.before.exists && !change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count - 1
}))
}
return null;
});
原因是因为每个云Firestore触发器都必须是幂等的,如Firestore文档所述:https://firebase.google.com/docs/functions/firestore-events#limitations_and_guarantees
因此,为了防止多次执行代码,您需要使用事件和事务进行管理。这是我处理大型收款柜台的特殊方式:
const executeOnce = (change, context, task) => {
const eventRef = firestore.collection('events').doc(context.eventId);
return firestore.runTransaction(t =>
t
.get(eventRef)
.then(docSnap => (docSnap.exists ? null : task(t)))
.then(() => t.set(eventRef, { processed: true }))
);
};
const documentCounter = collectionName => (change, context) =>
executeOnce(change, context, t => {
// on create
if (!change.before.exists && change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: ((docSnap.data() && docSnap.data().count) || 0) + 1
}));
// on delete
} else if (change.before.exists && !change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: docSnap.data().count - 1
}));
}
return null;
});
这里的用例:
/**
* Count documents in articles collection.
*/
exports.articlesCounter = functions.firestore
.document('articles/{id}')
.onWrite(documentCounter('articles'));
/**
* Count documents in customers collection.
*/
exports.customersCounter = functions.firestore
.document('customers/{id}')
.onWrite(documentCounter('customers'));
如您所见,防止重复执行的关键是上下文对象中名为 eventId 的属性。如果针对同一事件多次处理该函数,则事件ID在所有情况下均相同。不幸的是,您必须在数据库中具有“事件”集合。