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

如果是,我该怎么做?


当前回答

聚合计数查询刚刚在Firestore中预览。

在2022年Firebase峰会上宣布:https://firebase.blog/posts/2022/10/whats-new-at-Firebase-Sumit-2022

摘录:

[开发人员预览]Count()函数:与新的计数函数 Firstore[原文],你现在可以得到匹配文件的计数当你 运行查询或从集合中读取,而不加载实际的 文件,这为你节省了很多时间。

他们在峰会上展示的代码示例:

在问答环节中,有人问了汇总查询的定价问题,Firebase团队给出的答案是,它的成本是读取价格的1 / 1000(四舍四入到最近的读取,详情见下面的评论),但将计算汇总的所有记录。

其他回答

我同意@Matthew的观点,如果你执行这样的查询,成本会很高。

[开发者开始项目前的建议]

由于我们在一开始就预见到了这种情况,因此实际上可以用一个文档创建一个集合,即计数器,将所有计数器存储在一个类型为number的字段中。

例如:

对于集合上的每个CRUD操作,更新计数器文档:

当你创建一个新的集合/子集合时:(在计数器中+1)[1写操作] 当你删除一个集合/子集合时:(-1在计数器中)[1写操作] 当你更新一个现有的集合/子集合时,在counter文档上什么都不做:(0) 当你读取一个现有的集合/子集合时,在计数器文档上什么都不做:(0)

下一次,当您想要获得集合的数量时,您只需要查询/指向文档字段。[1读操作]

此外,你可以将集合的名称存储在一个数组中,但这将是棘手的,数组在firebase中的条件如下所示:

// we send this
['a', 'b', 'c', 'd', 'e']
// Firebase stores this
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}

// since the keys are numeric and sequential,
// if we query the data, we get this
['a', 'b', 'c', 'd', 'e']

// however, if we then delete a, b, and d,
// they are no longer mostly sequential, so
// we do not get back an array
{2: 'c', 4: 'e'}

所以,如果你不打算删除集合,你实际上可以使用数组来存储集合名称的列表而不是每次都查询所有的集合。

希望能有所帮助!

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

截至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)
}

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

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

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

querySnapshot.docs.length;

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

querySnapshot.empty;

使用admin. keystore . fieldvalue . Increment增加一个计数器:

exports.onInstanceCreate = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
  .onCreate((snap, context) =>
    db.collection('projects').doc(context.params.projectId).update({
      instanceCount: admin.firestore.FieldValue.increment(1),
    })
  );

exports.onInstanceDelete = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
  .onDelete((snap, context) =>
    db.collection('projects').doc(context.params.projectId).update({
      instanceCount: admin.firestore.FieldValue.increment(-1),
    })
  );

在本例中,每次将文档添加到instances子集合时,我们都会增加项目中的instanceCount字段。如果该字段还不存在,它将被创建并增加到1。

增量在内部是事务性的,但如果需要更频繁地递增,则应该使用分布式计数器。

通常最好实现onCreate和onDelete而不是onWrite,因为你将调用onWrite进行更新,这意味着你在不必要的函数调用上花费了更多的钱(如果你更新了你的集合中的文档)。