是否可以使用新的Firebase数据库Cloud Firestore来计算一个集合有多少项?

如果是,我该怎么做?


当前回答

这使用计数来创建数字唯一ID。在我的使用中,我将永远不会递减,即使需要ID的文档被删除。

在需要唯一数值的集合创建时

用一个文档指定一个集合appData,只设置.doc id 在firebase防火控制台中将uniqueNumericIDAmount设置为0 使用doc.data()。uniqueNumericIDAmount + 1作为唯一的数字id 更新appData收集uniqueNumericIDAmount与firebase.firestore.FieldValue.increment(1)

firebase
    .firestore()
    .collection("appData")
    .doc("only")
    .get()
    .then(doc => {
        var foo = doc.data();
        foo.id = doc.id;

        // your collection that needs a unique ID
        firebase
            .firestore()
            .collection("uniqueNumericIDs")
            .doc(user.uid)// user id in my case
            .set({// I use this in login, so this document doesn't
                  // exist yet, otherwise use update instead of set
                phone: this.state.phone,// whatever else you need
                uniqueNumericID: foo.uniqueNumericIDAmount + 1
            })
            .then(() => {

                // upon success of new ID, increment uniqueNumericIDAmount
                firebase
                    .firestore()
                    .collection("appData")
                    .doc("only")
                    .update({
                        uniqueNumericIDAmount: firebase.firestore.FieldValue.increment(
                            1
                        )
                    })
                    .catch(err => {
                        console.log(err);
                    });
            })
            .catch(err => {
                console.log(err);
            });
    });

其他回答

Firebase/Firestore中的新功能提供了集合中的文档计数:

请参阅本线程以了解如何实现它,并提供了一个示例。

如何计算在一个集合中的Firebase Firestore与WHERE查询在react.js文档的数量

最简单的方法是读取“querySnapshot”的大小。

db.collection("cities").get().then(function(querySnapshot) {      
    console.log(querySnapshot.size); 
});

你也可以在querySnapshot中读取文档数组的长度。

querySnapshot.docs.length;

或者如果“querySnapshot”为空,则读取空值,将返回一个布尔值。

querySnapshot.empty;

我尝试了很多不同的方法。 最后,我改进了其中一种方法。 首先,您需要创建一个单独的集合并保存其中的所有事件。 其次,您需要创建一个由时间触发的新lambda。此lambda将计数事件集合中的事件并清除事件文档。 代码细节见文章。 https://medium.com/@ihor.malaniuk/how-to-count-documents-in-google-cloud-firestore-b0e65863aeca

对于大量的收藏,要仔细计算文件的数量。如果你想为每个收集都有一个预先计算好的计数器,那么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;
});

原因是每个云防火墙触发器都必须是幂等的,正如防火墙文档所示: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在所有情况下都是相同的。不幸的是,您的数据库中必须有“事件”集合。

有了新版本的Firebase,您现在可以运行聚合查询了! 简单的写

.count().get(); 

在您的询问之后。