在Firestore中是否可以运行聚合查询?

4

堆栈:

Ionic
Nodejs/Express
Cloud Firestore

我被任务写一个应用程序,能够接受以“天”为格式的日期和当天的余额,并使用Chart.js在图表中显示这些数据。有间隔按钮可以在“天”,“周”和“月”之间切换,以将日期分组到相应的间隔中。
目前使用1个集合都可以正常工作。 “天”和“周”都没问题,但是一旦我们到达带有大量数据的“月”时,Firestore会在我的后端中停止运行。它尝试轮询的数据量太大了。我目前在后端使用“天”对“周”和“月”进行聚合。
我在文档中找到的唯一聚合文档是:https://firebase.google.com/docs/firestore/solutions/aggregation,它没有给我结果,而是将其存储到集合中,这对我没有帮助。该应用程序可以更改单个日期的余额,这会导致事后余额发生波动-因此必须在间隔更改时生成值。
是否存在像这样的解决方案,还是我必须创建3个独立的集合(天/周/月)并轮询所需的集合?
2个回答

10
更新:自2022年10月起,Firestore支持使用聚合查询计算文档,在JavaScript中的写法如下:
const coll = collection(db, "cities");
const snapshot = await getCountFromServer(coll);
console.log('count: ', snapshot.data().count);

你还可以使用查询来限制计算的文档,就像这样:
const coll = collection(db, "cities");
const query_ = query(coll, where('state', '==', 'CA'));
const snapshot = await getCountFromServer(query_);
console.log('count: ', snapshot.data().count);

当您使用count()操作时,每计算1,000个文档,您将被收取1个文档读取费用,但每个count()操作至少需要1个文档读取费用。计数操作的最长执行时间为60秒,超过该时间将超时。有关性能测试,请参见Cloud Firestore中计数文档的速度有多快?
出于性能和成本考虑,当需要计算大量用户的项目时,通常仍然需要使用其他方法,因此我将保留下面的先前答案。
更新:自2023年底以来,还可以在读取时跨多个Firestore文档计算总和和平均值。我建议查看关于使用聚合查询汇总数据的文档和我的帖子:如何处理Firestore中的聚合值
之前的回答:
根据你提供的链接docs

Cloud Firestore不支持原生的聚合查询。

所以这基本上回答了你标题中的问题:Firestore没有内置的能力在数据库服务器上运行聚合操作。
常见的解决方案有:
  1. 在客户端上运行聚合操作

    听起来你现在正在做的就是:你正在下载所有内部数据,然后在客户端上进行聚合。这种方法对于小数据集来说效果很好,但是如果你只是在客户端上显示聚合结果,那么你可能会下载比实际需要的数据要多得多。所以,如果你的数据集可能很大(当你使用Firestore时通常会变得很大),你应该考虑其他选择。

  2. 每次数据更改时更新聚合结果

    在这种情况下,你将聚合值存储在数据库中,并在写入需要聚合的值时更新它。文档中展示了使用这种方式计算移动平均值的示例,这种方式根本不需要查询,因此可以适用于任何大小的数据集。

    在这种情况下,你需要记住Firestore每秒只能执行大约一次写入操作。所以,如果你的数据量超过这个限制,你可能需要像文档中展示的分布式计数器那样分布你的聚合查询。

  3. 使用另一个数据库进行聚合查询

    另一种选择是将Firestore用于存储客户端读取的数据,但使用另一个数据库进行复杂的动态查询。

    一个典型的例子是将数据从Firestore导出到BigQuery,然后在BigQuery中进行计算,并将结果写回Firestore,以便客户端可以读取它们。在这种情况下,你将两个产品用于它们最擅长的领域:Firestore用于大规模数据服务,BigQuery用于大规模数据处理。


感谢您更新的答案,非常有帮助(特别是成本方面)。 - tooward

4

最近Firestore发布了聚合查询功能,基本上允许您在Firestore集合上执行count()操作。

以下是从他们的文档中摘录的示例:

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

// expected output: amount of cities in my collection

count() 在 Firestore 中有几个限制,我会提到其中两个:

  • 执行时间: count() 必须在 60 秒内解决。否则会抛出错误
  • 价格:每计数 1000 个文档,需要消耗 1 个文档读取。因此,如果您的 count() 已经读取了 2000 个文档,则将花费您 2 个文档读取。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接