如何获取集合中的文档数量? [复制]

Posted

技术标签:

【中文标题】如何获取集合中的文档数量? [复制]【英文标题】:How to get count of documents in a collection? [duplicate] 【发布时间】:2018-10-03 10:02:29 【问题描述】:

如果我的集合中有大量文档,我是否可以在不加载整个集合的情况下获取文档数。

db.collection('largecollection').get().then(snapshot => 
   length = snapshot.size;
)

【问题讨论】:

您可以使用云函数在每次将文档添加到集合时更新计数器(以及每次删除文档时,如有必要) 我想你可能也对这篇文章感兴趣,How to count the number of documents in a Firestore collection?。 【参考方案1】:

没有用于获取集合中文档数量的内置 API。因此,默认情况下,您必须下载所有文档才能计算它们。

正如 Renaud 所评论的,解决此问题的常见解决方法是保留一个单独的计数器,每次添加/删除文档时都会更新该计数器。您可以在您的应用程序中执行此操作,updating the counter with a transaction 每次添加/删除文档时。但在服务器中执行此操作更可靠,例如 Cloud Functions for Firebase。有关此方法的示例,请参阅the functions-samples repo。虽然该示例适用于 Firebase 实时数据库,但该方法同样适用于 Firestore。

另请参阅 distributed counters 上的 Firestore 文档部分。

【讨论】:

【参考方案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;
);

原因是因为每个 Cloud 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 在所有情况下都相同。不幸的是,您的数据库中必须有“事件”集合。

【讨论】:

***.com/questions/46554091/…

以上是关于如何获取集合中的文档数量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Firestore 集合中获取所有文档并将它们返回到数组列表中? [复制]

Firestore - 如何在不真正获取所有文档的情况下找到可以使用查询获取的文档数量? [复制]

如何获取分区中的元素数量? [复制]

如何在 MongoDB 中获取集合的计数?

如何获取 JavaScript 字典中的键集合? [复制]

如何获取文件夹中文件的数量? [复制]