聚合查询会处理多个已编入索引的实体中的数据,然后返回单个摘要值。Datastore 模式 Firestore 支持以下聚合查询:
count()
sum()
avg()
聚合查询可简化应用代码,并且与提取每个实体进行处理相比,费用更低。请阅读本页,了解如何使用聚合查询。
count()
聚合
使用 count()
聚合可返回与给定查询匹配的已编入索引的实体的总数。例如,此 count()
聚合会返回某种类中的实体总数。
Java
Python
Go
aggregationCountQuery := datastore.NewQuery("Task"). NewAggregationQuery(). WithCount("total_tasks") countResults, err := client.RunAggregationQuery(ctx, aggregationCountQuery) count := countResults["total_tasks"] countValue := count.(*datastorepb.Value) fmt.Printf("Number of results from query: %d\n", countValue.GetIntegerValue())
GQL
AGGREGATE COUNT(*) AS total OVER ( SELECT * AS total FROM tasks )
GQL 支持简化形式的 count()
查询:
SELECT COUNT(*) AS total FROM tasks
此示例使用了 total
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
count()
聚合会考虑查询的所有过滤条件以及所有 limit
子句。例如,以下聚合会返回与给定过滤条件匹配的实体的数量。
Java
Python
Go
aggregationCountQuery := datastore.NewQuery("Task"). FilterField("done", "=", true). NewAggregationQuery(). WithCount("total_tasks_done") countResults, err := client.RunAggregationQuery(ctx, aggregationCountQuery) count := countResults["total_tasks_done"] countValue := count.(*datastorepb.Value) fmt.Printf("Number of results from query: %d\n", countValue.GetIntegerValue())
GQL
AGGREGATE COUNT(*) OVER ( SELECT * FROM tasks WHERE is_done = false AND tag = 'house')
GQL 支持简化形式的 count()
查询:
SELECT COUNT(*) AS total FROM tasks WHERE is_done = false AND tag = 'house'
此示例使用了 total
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
此示例展示了如何计数到某个值。例如,您可以使用此属性在达到某个数字时停止计数,并告知用户他们已超出该数字。
Java
Python
Go
aggregationCountQuery := datastore.NewQuery("Task"). Limit(2). NewAggregationQuery(). WithCount("at_least") countResults, err := client.RunAggregationQuery(ctx, aggregationCountQuery) count := countResults["at_least"] countValue := count.(*datastorepb.Value) fmt.Printf("We have at least %d tasks\n", countValue.GetIntegerValue())
GQL
AGGREGATE COUNT_UP_TO(1000) OVER ( SELECT * FROM tasks WHERE is_done = false)
GQL 支持简化形式的 count_up_to()
查询:
SELECT COUNT_UP_TO(1000) AS total FROM tasks WHERE is_done = false AND tag = 'house'
此示例使用了 total
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
sum()
聚合
使用 sum()
聚合可返回与给定查询匹配的数值的总和。例如,以下 sum()
聚合会返回给定种类的实体的给定属性的数值总和:
Java
Python
Go
aggregationSumQuery := datastore.NewQuery("Task"). NewAggregationQuery(). WithSum("hours", "total_hours") sumResults, err := client.RunAggregationQuery(ctx, aggregationSumQuery) sum := sumResults["total_hours"] sumValue := sum.(*datastorepb.Value) fmt.Printf("Sum of results from query: %d\n", sumValue.GetIntegerValue())
GQL
AGGREGATE SUM(hours) AS total_hours OVER ( SELECT * FROM tasks )
GQL 支持简化形式的 sum()
查询:
SELECT SUM(hours) AS total_hours FROM tasks
此示例使用了 total_hours
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
sum()
聚合会考虑查询的所有过滤条件以及所有 limit
子句。例如,以下聚合会返回与指定过滤条件匹配的实体中具有数值的指定属性的总和。
Java
Python
此查询需要以下索引:
- kind: Task properties: - name: done - name: hours
Go
aggregationSumQuery := datastore.NewQuery("Task"). FilterField("done", "=", false). FilterField("tag", "=", "house"). NewAggregationQuery(). WithSum("hours", "total_hours") sumResults, err := client.RunAggregationQuery(ctx, aggregationSumQuery) sum := sumResults["total_hours"] sumValue := sum.(*datastorepb.Value) fmt.Printf("Sum of results from query: %d\n", sumValue.GetIntegerValue())
GQL
AGGREGATE SUM(hours) AS total_hours OVER ( SELECT * FROM tasks WHERE is_done = false AND tag = 'house' )
GQL 支持简化形式的 sum()
查询:
SELECT SUM(hours) AS total_hours FROM tasks WHERE is_done = false AND tag = 'house'
此示例使用了 total_hours
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
avg()
聚合
使用 avg()
聚合可返回与给定查询匹配的数值的平均值。例如,以下 avg()
聚合会返回与查询匹配的实体的数值属性值的算术平均值:
Java
Python
Go
aggregationAvgQuery := datastore.NewQuery("Task"). NewAggregationQuery(). WithAvg("hours", "avg_hours") avgResults, err := client.RunAggregationQuery(ctx, aggregationAvgQuery) avg := avgResults["avg_hours"] avgValue := avg.(*datastorepb.Value) fmt.Printf("average hours: %f\n", avgValue.GetDoubleValue())
GQL
AGGREGATE AVG(hours) as avg_hours OVER ( SELECT * FROM tasks )
GQL 支持简化形式的 avg()
查询:
SELECT AVG(hours) as avg_hours
此示例使用了 avg_hours
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
avg()
聚合会考虑查询的所有过滤条件以及所有 limit
子句。例如,以下聚合会返回与查询过滤条件匹配的实体的数值属性值中指定属性的算术平均值。
Java
Python
此查询需要以下索引:
- kind: Task properties: - name: done - name: hours
Go
aggregationAvgQuery := datastore.NewQuery("Task"). FilterField("done", "=", false). FilterField("tag", "=", "house"). NewAggregationQuery(). WithAvg("hours", "avg_hours") avgResults, err := client.RunAggregationQuery(ctx, aggregationAvgQuery) avg := avgResults["avg_hours"] avgValue := avg.(*datastorepb.Value) fmt.Printf("average hours: %f\n", avgValue.GetDoubleValue())
GQL
AGGREGATE AVG(hours) as avg_hours OVER ( SELECT * FROM tasks WHERE is_done = false AND tag = 'house' )
GQL 支持简化形式的 avg()
查询:
SELECT AVG(hours) as avg_hours FROM tasks WHERE is_done = false AND tag = 'house'
此示例使用了 avg_hours
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
在查询中计算多项聚合
您可以将多项聚合合并到一个聚合流水线中。这样可以减少所需的索引读取次数。如果查询包含多个字段的聚合,则查询需要复合索引,并且每个聚合计算仅包含那些包含每个聚合所用所有字段的实体。
以下示例在单个聚合查询中执行多次聚合:
Java
Python
Go
aggregationQuery := datastore.NewQuery("Task"). NewAggregationQuery(). WithCount("total_tasks"). WithSum("hours", "total_hours"). WithAvg("hours", "avg_hours") Results, err := client.RunAggregationQuery(ctx, aggregationQuery) fmt.Printf("Number of results from query: %d\n", Results["total_tasks"].(*datastorepb.Value).GetIntegerValue()) fmt.Printf("Sum of results from query: %d\n", Results["total_hours"].(*datastorepb.Value).GetIntegerValue()) fmt.Printf("Avg of results from query: %f\n", Results["avg_hours"].(*datastorepb.Value).GetDoubleValue())
GQL
AGGREGATE SUM(hours) AS total_hours, COUNT(*) AS total_tasks OVER ( SELECT * FROM tasks WHERE is_done = false AND tag = 'house' )
GQL 支持一种简化的聚合查询形式:
SELECT SUM(hours) AS total_hours, COUNT(*) AS total_tasks FROM tasks WHERE is_done = false AND tag = 'house'
此示例使用 total_hours
和 total_tasks
的可选别名。
简化形式仅支持 FROM
和 WHERE
子句。如需了解详情,请参阅 GQL 参考文档。
具有多项聚合的查询仅包含此类实体,即包含每个聚合中所有属性的实体。这可能会导致单独执行每次聚合时得到不同的结果。
行为和限制
在使用聚合查询时,请注意以下行为和限制:
- 您提供给聚合的查询必须符合查询限制。
如果聚合查询无法在 60 秒内完成解析,则会返回
DEADLINE_EXCEEDED
错误。聚合性能取决于您的索引配置以及数据集的规模。如果操作无法在 60 秒时限内完成,作为一种可能的解决方法,您可以利用游标合并多个聚合。
聚合查询会从索引条目中读取数据,并且仅包含编入索引的属性。
如果向查询添加
OrderBy
子句,则查询只会对存在排序属性的实体进行聚合。在 GQL 中,简化形式不支持
ORDER BY
、LIMIT
或OFFSET
子句。在投影查询中,您只能汇总投影中的属性的数据。例如,在 GQL 查询
SELECT a, b FROM k WHERE c = 1
中,您只能汇总a
或b
中的数据。count()
聚合不会对具有数组属性的实体进行去重。 每个与查询匹配的数组值都会使计数增加 1。对于
sum()
和avg()
聚合,系统会忽略非数字值。sum()
和avg()
聚合仅考虑整数值、浮点值和时间戳。时间戳会转换为微秒整数值,用于sum()
、avg()
和预测。在单个查询中组合多项聚合时,请注意,
sum()
和avg()
会忽略非数字值,而count()
会包含非数字值。如果您合并针对不同属性的聚合,则计算将仅包含带所有这些属性的实体。这可能会导致单独执行每次聚合时得到不同的结果。
价格
count()
、sum()
和 avg()
聚合查询的价格取决于操作期间扫描到的索引条目的数量。对于匹配的索引条目(最多 1,000 个),系统会收取相当于一次实体读取的费用。后续匹配的索引条目会产生额外的读取单位费用。每次查询的最低费用为 1 个读取单位。如需了解价格信息,请参阅 Datastore 模式 Firestore 价格。
如果您在单个查询中组合了多个聚合,则该查询会针对每个聚合使用相同的索引,并对数据执行一次扫描。与单独执行每次聚合相比,这有助于减少需要付费的索引扫描和读取次数。不过,具有多项聚合的查询仅包含此类实体,即包含所有这些属性的实体。这可能会导致单独执行每次聚合时得到不同的结果。
后续步骤
- 了解查询。
- 了解 Datastore 模式 Firestore 的最佳实践。