聚合查询会处理多个已编入索引的实体中的数据,然后返回单个摘要值。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 的最佳实践。