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

如果是,我该怎么做?


当前回答

解决办法是:

在firebase文档中编写一个计数器,每次创建新条目时都在事务中增加计数器

您将计数存储在新条目的字段中(即:position: 4)。

然后在该字段上创建一个索引(position DESC)。

您可以对查询执行跳过+限制操作。Where("position", "<" x).OrderBy("position", DESC)

希望这能有所帮助!

其他回答

截至2022年10月,Firestore在客户端sdk上引入了count()方法。现在您可以在没有下载的情况下计算查询。

对于1000份文件,它将收取你阅读1份文件的费用。

网络(v9)

Firebase 9.11.0介绍:

const collectionRef = collection(db, "cities");
const snapshot = await getCountFromServer(collectionRef);
console.log('count: ', snapshot.data().count);

Web V8

不可用。

节点(管理)

const collectionRef = db.collection('cities');
const snapshot = await collectionRef.count().get();
console.log(snapshot.data().count);

Android (Kotlin)

在firestore v24.4.0 (BoM 31.0.0)引入:

val query = db.collection("cities")
val countQuery = query.count()
countQuery.get(AggregateSource.SERVER).addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val snapshot = task.result
        Log.d(TAG, "Count: ${snapshot.count}")
    } else {
        Log.d(TAG, "Count failed: ", task.getException())
    }
}

苹果平台(Swift)

Firestore v10.0.0引入:

do {
  let query = db.collection("cities")
  let countQuery = query.countAggregateQuery
  let snapshot = try await countQuery.aggregation(source: AggregateSource.server)
  print(snapshot.count)
} catch {
  print(error)
}

这使用计数来创建数字唯一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);
            });
    });

据我所知,目前还没有内置的解决方案,只能在节点sdk中实现。 如果你有

db.collection('someCollection')

你可以使用

.select([fields])

定义要选择的字段。如果执行空select(),则只会得到一个文档引用数组。

例子:

db.collection (someCollection) .select () . get () ( (snapshot) => console.log(snapshot.docs.length) );

此解决方案只是针对下载所有文档的最坏情况的优化,并且不能扩展到大型集合!

再看看这个: 如何获得在一个集合与云Firestore的文件的数量计数

解决办法是:

在firebase文档中编写一个计数器,每次创建新条目时都在事务中增加计数器

您将计数存储在新条目的字段中(即:position: 4)。

然后在该字段上创建一个索引(position DESC)。

您可以对查询执行跳过+限制操作。Where("position", "<" x).OrderBy("position", DESC)

希望这能有所帮助!

不,目前还没有内置的聚合查询支持。然而,有几件事你可以做。

这里记录了第一个。您可以使用事务或云函数来维护聚合信息:

这个例子展示了如何使用一个函数来跟踪子集合中的评级数量,以及平均评级。

exports.aggregateRatings = firestore
  .document('restaurants/{restId}/ratings/{ratingId}')
  .onWrite(event => {
    // Get value of the newly added rating
    var ratingVal = event.data.get('rating');

    // Get a reference to the restaurant
    var restRef = db.collection('restaurants').document(event.params.restId);

    // Update aggregations in a transaction
    return db.transaction(transaction => {
      return transaction.get(restRef).then(restDoc => {
        // Compute new number of ratings
        var newNumRatings = restDoc.data('numRatings') + 1;

        // Compute new average rating
        var oldRatingTotal = restDoc.data('avgRating') * restDoc.data('numRatings');
        var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;

        // Update restaurant info
        return transaction.update(restRef, {
          avgRating: newAvgRating,
          numRatings: newNumRatings
        });
      });
    });
});

jbb提到的解决方案在您只想不频繁地计数文档时也很有用。确保使用select()语句来避免下载所有文档(当您只需要一个计数时,这是很大的带宽)。select()目前仅在服务器sdk中可用,因此该解决方案不适用于移动应用程序。