Summarize data with aggregation queries

An aggregation query processes the data from multiple index entries to return a single summary value.

Cloud Firestore supports the following aggregation queries:

  • count()
  • sum()
  • average()

Cloud Firestore calculates the aggregation and transmits only the result back to your application. Compared to executing a full query and calculating the aggregation in your app, aggregation queries save on both billed document reads and bytes transferred.

Aggregation queries rely on the existing index configuration that your queries already use, and scale proportionally to the number of index entries scanned. Latency increases with the number of items in the aggregation.

Use the count() aggregation

The count() aggregation query lets you determine the number of documents in a collection or query.

For more information about the example data, see Getting data.

The following count() aggregation returns the total number of cities in the cities collection.

Web

constcoll=collection(db,"cities");constsnapshot=awaitgetCountFromServer(coll);console.log('count: ',snapshot.data().count);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities")letcountQuery=query.countdo{letsnapshot=tryawaitcountQuery.getAggregation(source:.server)print(snapshot.count)}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRCollectionReference*query=[self.dbcollectionWithPath:@"cities"];[query.countaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching count: %@",error);}else{NSLog(@"Cities count: %@",snapshot.count);}}];

Java

Queryquery=db.collection("cities");AggregateQuerycountQuery=query.count();countQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Count fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Count: "+snapshot.getCount());}else{Log.d(TAG,"Count failed: ",task.getException());}}});

Kotlin

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

Dart

// Returns number of documents in users collectiondb.collection("cities").count().get().then((res)=>print(res.count),onError:(e)=>print("Error completing: $e"),);
Go
packagefirestoreimport("context""errors""fmt""io""cloud.google.com/go/firestore"firestorepb"cloud.google.com/go/firestore/apiv1/firestorepb")funccreateCountQuery(wio.Writer,projectIDstring)error{// Instantiate the clientctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850)// `alias` argument--"all"--provides a key for accessing the aggregate query// results. The alias value must be unique across all aggregation aliases in// an aggregation query and must conform to allowed Document field names.//// See https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#document for details.aggregationQuery:=query.NewAggregationQuery().WithCount("all")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}count,ok:=results["all"]if!ok{returnerrors.New("firestore: couldn't get alias for COUNT from results")}countValue:=count.(*firestorepb.Value)fmt.Fprintf(w,"Number of results from query: %d\n",countValue.GetIntegerValue())returnnil}
Java
CollectionReferencecollection=db.collection("cities");AggregateQuerySnapshotsnapshot=collection.count().get().get();System.out.println("Count: "+snapshot.getCount());
Node.js
constcollectionRef=db.collection('cities');constsnapshot=awaitcollectionRef.count().get();console.log(snapshot.data().count);
Python
fromgoogle.cloudimportfirestorefromgoogle.cloud.firestore_v1importaggregationfromgoogle.cloud.firestore_v1.base_queryimportFieldFilterdefcreate_count_query(project_id:str)-> None:"""Builds an aggregate query that returns the number of results in the query. Arguments: project_id: your Google Cloud Project ID """client=firestore.Client(project=project_id)collection_ref=client.collection("users")query=collection_ref.where(filter=FieldFilter("born",">",1800))aggregate_query=aggregation.AggregationQuery(query)# `alias` to provides a key for accessing the aggregate query resultsaggregate_query.count(alias="all")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Number of results from query: {result[0].value}")

The count() aggregation takes into account any filters on the query and any limit clauses.

Web

constcoll=collection(db,"cities");constq=query(coll,where("state","==","CA"));constsnapshot=awaitgetCountFromServer(q);console.log('count: ',snapshot.data().count);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities").whereField("state",isEqualTo:"CA")letcountQuery=query.countdo{letsnapshot=tryawaitcountQuery.getAggregation(source:.server)print(snapshot.count)}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[[self.dbcollectionWithPath:@"cities"]queryWhereField:@"state"isEqualTo:@"CA"];[query.countaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching count: %@",error);}else{NSLog(@"Cities count: %@",snapshot.count);}}];

Java

Queryquery=db.collection("cities").whereEqualTo("state","CA");AggregateQuerycountQuery=query.count();countQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Count fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Count: "+snapshot.getCount());}else{Log.d(TAG,"Count failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities").whereEqualTo("state","CA")valcountQuery=query.count()countQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Count fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Count: ${snapshot.count}")}else{Log.d(TAG,"Count failed: ",task.getException())}}

Dart

// This also works with collection queries.db.collection("cities").where("capital",isEqualTo:10).count().get().then((res)=>print(res.count),onError:(e)=>print("Error completing: $e"),);
Go
packagefirestoreimport("context""errors""fmt""io""cloud.google.com/go/firestore"firestorepb"cloud.google.com/go/firestore/apiv1/firestorepb")funccreateCountQuery(wio.Writer,projectIDstring)error{// Instantiate the clientctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850)// `alias` argument--"all"--provides a key for accessing the aggregate query// results. The alias value must be unique across all aggregation aliases in// an aggregation query and must conform to allowed Document field names.//// See https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#document for details.aggregationQuery:=query.NewAggregationQuery().WithCount("all")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}count,ok:=results["all"]if!ok{returnerrors.New("firestore: couldn't get alias for COUNT from results")}countValue:=count.(*firestorepb.Value)fmt.Fprintf(w,"Number of results from query: %d\n",countValue.GetIntegerValue())returnnil}
Java
CollectionReferencecollection=db.collection("cities");Queryquery=collection.whereEqualTo("state","CA");AggregateQuerySnapshotsnapshot=query.count().get().get();System.out.println("Count: "+snapshot.getCount());
Node.js
constcollectionRef=db.collection('cities');constquery=collectionRef.where('state','==','CA');constsnapshot=awaitquery.count().get();console.log(snapshot.data().count);
Python
fromgoogle.cloudimportfirestorefromgoogle.cloud.firestore_v1importaggregationfromgoogle.cloud.firestore_v1.base_queryimportFieldFilterdefcreate_count_query(project_id:str)-> None:"""Builds an aggregate query that returns the number of results in the query. Arguments: project_id: your Google Cloud Project ID """client=firestore.Client(project=project_id)collection_ref=client.collection("users")query=collection_ref.where(filter=FieldFilter("born",">",1800))aggregate_query=aggregation.AggregationQuery(query)# `alias` to provides a key for accessing the aggregate query resultsaggregate_query.count(alias="all")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Number of results from query: {result[0].value}")

Use the sum() aggregation

Use the sum() aggregation to return the total sum of numeric values that match a given query—for example:

Web

constcoll=collection(firestore,'cities');constsnapshot=awaitgetAggregateFromServer(coll,{totalPopulation:sum('population')});console.log('totalPopulation: ',snapshot.data().totalPopulation);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities")letaggregateQuery=query.aggregate([AggregateField.sum("population")])do{letsnapshot=tryawaitaggregateQuery.getAggregation(source:.server)print(snapshot.get(AggregateField.sum("population")))}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[self.dbcollectionWithPath:@"cities"];FIRAggregateQuery*aggregateQuery=[queryaggregate:@[[FIRAggregateFieldaggregateFieldForSumOfField:@"population"]]];[aggregateQueryaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching aggregate: %@",error);}else{NSLog(@"Sum: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForSumOfField:@"population"]]);}}];

Java

Queryquery=db.collection("cities");AggregateQueryaggregateQuery=query.aggregate(AggregateField.sum("population"));aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Aggregate fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Sum: "+snapshot.get(AggregateField.sum("population")));}else{Log.d(TAG,"Aggregation failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities")valaggregateQuery=query.aggregate(AggregateField.sum("population"))aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Aggregate fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Sum: ${snapshot.get(AggregateField.sum("population"))}")}else{Log.d(TAG,"Aggregate failed: ",task.getException())}}

Dart

db.collection("cities").aggregate(sum("population")).get().then((res)=>print(res.getAverage("population")),onError:(e)=>print("Error completing: $e"),);
Java
collection=db.collection("cities");snapshot=collection.aggregate(sum("population")).get().get();System.out.println("Sum: "+snapshot.get(sum("population")));
Node.js
constcoll=firestore.collection('cities');constsumAggregateQuery=coll.aggregate({totalPopulation:AggregateField.sum('population'),});constsnapshot=awaitsumAggregateQuery.get();console.log('totalPopulation: ',snapshot.data().totalPopulation);
Python
collection_ref=client.collection("users")aggregate_query=aggregation.AggregationQuery(collection_ref)aggregate_query.sum("coins",alias="sum")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Sum of results from query: {result[0].value}")
Go
funccreateSumQuery(wio.Writer,projectIDstring)error{ctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850)aggregationQuery:=query.NewAggregationQuery().WithSum("coins","sum_coins")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}sum,ok:=results["sum_coins"]if!ok{returnerrors.New("firestore: couldn't get alias for SUM from results")}sumValue:=sum.(*firestorepb.Value)fmt.Fprintf(w,"Sum of results from query: %d\n",sumValue.GetIntegerValue())returnnil}

The sum() aggregation takes into account any filters on the query and any limit clauses—for example:

Web

constcoll=collection(firestore,'cities');constq=query(coll,where('capital','==',true));constsnapshot=awaitgetAggregateFromServer(q,{totalPopulation:sum('population')});console.log('totalPopulation: ',snapshot.data().totalPopulation);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities").whereField("capital",isEqualTo:true)letaggregateQuery=query.aggregate([AggregateField.sum("population")])do{letsnapshot=tryawaitaggregateQuery.getAggregation(source:.server)print(snapshot.get(AggregateField.sum("population")))}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[[self.dbcollectionWithPath:@"cities"]queryWhereFilter:[FIRFilterfilterWhereField:@"capital"isEqualTo:@YES]];FIRAggregateQuery*aggregateQuery=[queryaggregate:@[[FIRAggregateFieldaggregateFieldForSumOfField:@"population"]]];[aggregateQueryaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching aggregate: %@",error);}else{NSLog(@"Sum: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForSumOfField:@"population"]]);}}];

Java

Queryquery=db.collection("cities").whereEqualTo("capital",true);AggregateQueryaggregateQuery=query.aggregate(AggregateField.sum("population"));aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Aggregate fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Sum: "+snapshot.get(AggregateField.sum("population")));}else{Log.d(TAG,"Aggregation failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities").whereEqualTo("capital",true)valaggregateQuery=query.aggregate(AggregateField.sum("population"))aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Aggregate fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Sum: ${snapshot.get(AggregateField.sum("population"))}")}else{Log.d(TAG,"Aggregate failed: ",task.getException())}}

Dart

db.collection("cities").where("capital",isEqualTo:true).aggregate(sum("population")).get().then((res)=>print(res.getAverage("population")),onError:(e)=>print("Error completing: $e"),);
Java
collection=db.collection("cities");query=collection.whereEqualTo("state","CA");snapshot=query.aggregate(sum("population")).get().get();System.out.println("Sum: "+snapshot.get(sum("population")));
Node.js
constcoll=firestore.collection('cities');constq=coll.where("capital","==",true);constsumAggregateQuery=q.aggregate({totalPopulation:AggregateField.sum('population'),});constsnapshot=awaitsumAggregateQuery.get();console.log('totalPopulation: ',snapshot.data().totalPopulation);
Python
collection_ref=client.collection("users")query=collection_ref.where(filter=FieldFilter("people","==","Matthew"))aggregate_query=aggregation.AggregationQuery(query)aggregate_query.sum("coins",alias="sum")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Sum of results from query: {result[0].value}")
Go
funccreateSumQuery(wio.Writer,projectIDstring)error{ctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850).Limit(5)aggregationQuery:=query.NewAggregationQuery().WithSum("coins","sum_coins")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}sum,ok:=results["sum_coins"]if!ok{returnerrors.New("firestore: couldn't get alias for SUM from results")}sumValue:=sum.(*firestorepb.Value)fmt.Fprintf(w,"Sum of results from query: %d\n",sumValue.GetIntegerValue())returnnil}

Use the average() aggregation

Use the average() aggregation to return the average of numeric values that match a given query, for example:

Web

constcoll=collection(firestore,'cities');constsnapshot=awaitgetAggregateFromServer(coll,{averagePopulation:average('population')});console.log('averagePopulation: ',snapshot.data().averagePopulation);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities")letaggregateQuery=query.aggregate([AggregateField.average("population")])do{letsnapshot=tryawaitaggregateQuery.getAggregation(source:.server)print(snapshot.get(AggregateField.average("population")))}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[self.dbcollectionWithPath:@"cities"];FIRAggregateQuery*aggregateQuery=[queryaggregate:@[[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]];[aggregateQueryaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching aggregate: %@",error);}else{NSLog(@"Avg: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]);}}];

Java

Queryquery=db.collection("cities");AggregateQueryaggregateQuery=query.aggregate(AggregateField.average("population"));aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Aggregate fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Average: "+snapshot.get(AggregateField.average("population")));}else{Log.d(TAG,"Aggregation failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities")valaggregateQuery=query.aggregate(AggregateField.average("population"))aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Aggregate fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Average: ${snapshot.get(AggregateField.average("population"))}")}else{Log.d(TAG,"Aggregate failed: ",task.getException())}}

Dart

db.collection("cities").aggregate(average("population")).get().then((res)=>print(res.getAverage("population")),onError:(e)=>print("Error completing: $e"),);
Java
collection=db.collection("cities");snapshot=collection.aggregate(average("population")).get().get();System.out.println("Average: "+snapshot.get(average("population")));
Node.js
constcoll=firestore.collection('cities');constaverageAggregateQuery=coll.aggregate({averagePopulation:AggregateField.average('population'),});constsnapshot=awaitaverageAggregateQuery.get();console.log('averagePopulation: ',snapshot.data().averagePopulation);
Python
collection_ref=client.collection("users")aggregate_query=aggregation.AggregationQuery(collection_ref)aggregate_query.avg("coins",alias="avg")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Average of results from query: {result[0].value}")
Go
funccreateAvgQuery(wio.Writer,projectIDstring)error{ctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850)aggregationQuery:=query.NewAggregationQuery().WithAvg("coins","avg_coins")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}avg,ok:=results["avg_coins"]if!ok{returnerrors.New("firestore: couldn't get alias for AVG from results")}avgValue:=avg.(*firestorepb.Value)fmt.Fprintf(w,"Avg of results from query: %d\n",avgValue.GetDoubleValue())returnnil}

The average() aggregation takes into account any filters on the query and any limit clauses, for example:

Web

constcoll=collection(firestore,'cities');constq=query(coll,where('capital','==',true));constsnapshot=awaitgetAggregateFromServer(q,{averagePopulation:average('population')});console.log('averagePopulation: ',snapshot.data().averagePopulation);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities").whereField("capital",isEqualTo:true)letaggregateQuery=query.aggregate([AggregateField.average("population")])do{letsnapshot=tryawaitaggregateQuery.getAggregation(source:.server)print(snapshot.get(AggregateField.average("population")))}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[[self.dbcollectionWithPath:@"cities"]queryWhereFilter:[FIRFilterfilterWhereField:@"capital"isEqualTo:@YES]];FIRAggregateQuery*aggregateQuery=[queryaggregate:@[[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]];[aggregateQueryaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching aggregate: %@",error);}else{NSLog(@"Avg: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]);}}];

Java

Queryquery=db.collection("cities").whereEqualTo("capital",true);AggregateQueryaggregateQuery=query.aggregate(AggregateField.average("population"));aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Aggregate fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Average: "+snapshot.get(AggregateField.average("population")));}else{Log.d(TAG,"Aggregation failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities").whereEqualTo("capital",true)valaggregateQuery=query.aggregate(AggregateField.average("population"))aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Aggregate fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Average: ${snapshot.get(AggregateField.average("population"))}")}else{Log.d(TAG,"Aggregate failed: ",task.getException())}}

Dart

db.collection("cities").where("capital",isEqualTo:true).aggregate(average("population")).get().then((res)=>print(res.getAverage("population")),onError:(e)=>print("Error completing: $e"),);
Java
collection=db.collection("cities");query=collection.whereEqualTo("state","CA");snapshot=query.aggregate(average("population")).get().get();System.out.println("Average: "+snapshot.get(average("population")));
Node.js
constcoll=firestore.collection('cities');constq=coll.where("capital","==",true);constaverageAggregateQuery=q.aggregate({averagePopulation:AggregateField.average('population'),});constsnapshot=awaitaverageAggregateQuery.get();console.log('averagePopulation: ',snapshot.data().averagePopulation);
Python
collection_ref=client.collection("users")query=collection_ref.where(filter=FieldFilter("people","==","Matthew"))aggregate_query=aggregation.AggregationQuery(query)aggregate_query.avg("coins",alias="avg")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Average of results from query: {result[0].value}")
Go
funccreateAvgQuery(wio.Writer,projectIDstring)error{ctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850).Limit(5)aggregationQuery:=query.NewAggregationQuery().WithAvg("coins","avg_coins")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}avg,ok:=results["avg_coins"]if!ok{returnerrors.New("firestore: couldn't get alias for AVG from results")}avgValue:=avg.(*firestorepb.Value)fmt.Fprintf(w,"Avg of results from query: %d\n",avgValue.GetDoubleValue())returnnil}

Calculate multiple aggregations in a query

You can combine multiple aggregations in a single aggregation pipeline. This can reduce the number of index reads required. If the query includes aggregations on multiple fields, the query might requires a composite index. In that case, Cloud Firestore suggests an index.

The following example performs multiple aggregations in a single aggregation query:

Web

constcoll=collection(firestore,'cities');constsnapshot=awaitgetAggregateFromServer(coll,{countOfDocs:count(),totalPopulation:sum('population'),averagePopulation:average('population')});console.log('countOfDocs: ',snapshot.data().countOfDocs);console.log('totalPopulation: ',snapshot.data().totalPopulation);console.log('averagePopulation: ',snapshot.data().averagePopulation);
Swift
Note: This product is not available on watchOS and App Clip targets.
letquery=db.collection("cities")letaggregateQuery=query.aggregate([AggregateField.count(),AggregateField.sum("population"),AggregateField.average("population")])do{letsnapshot=tryawaitaggregateQuery.getAggregation(source:.server)print("Count: \(snapshot.get(AggregateField.count()))")print("Sum: \(snapshot.get(AggregateField.sum("population")))")print("Average: \(snapshot.get(AggregateField.average("population")))")}catch{print(error)}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRQuery*query=[self.dbcollectionWithPath:@"cities"];FIRAggregateQuery*aggregateQuery=[queryaggregate:@[[FIRAggregateFieldaggregateFieldForCount],[FIRAggregateFieldaggregateFieldForSumOfField:@"population"],[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]];[aggregateQueryaggregationWithSource:FIRAggregateSourceServercompletion:^(FIRAggregateQuerySnapshot*snapshot,NSError*error){if(error!=nil){NSLog(@"Error fetching aggregate: %@",error);}else{NSLog(@"Count: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForCount]]);NSLog(@"Sum: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForSumOfField:@"population"]]);NSLog(@"Avg: %@",[snapshotvalueForAggregateField:[FIRAggregateFieldaggregateFieldForAverageOfField:@"population"]]);}}];

Java

Queryquery=db.collection("cities");AggregateQueryaggregateQuery=query.aggregate(AggregateField.count(),AggregateField.sum("population"),AggregateField.average("population"));aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener(newOnCompleteListener<AggregateQuerySnapshot>(){@OverridepublicvoidonComplete(@NonNullTask<AggregateQuerySnapshot>task){if(task.isSuccessful()){// Aggregate fetched successfullyAggregateQuerySnapshotsnapshot=task.getResult();Log.d(TAG,"Count: "+snapshot.get(AggregateField.count()));Log.d(TAG,"Sum: "+snapshot.get(AggregateField.sum("population")));Log.d(TAG,"Average: "+snapshot.get(AggregateField.average("population")));}else{Log.d(TAG,"Aggregation failed: ",task.getException());}}});

Kotlin

valquery=db.collection("cities")valaggregateQuery=query.aggregate(AggregateField.count(),AggregateField.sum("population"),AggregateField.average("population"))aggregateQuery.get(AggregateSource.SERVER).addOnCompleteListener{task-> if(task.isSuccessful){// Aggregate fetched successfullyvalsnapshot=task.resultLog.d(TAG,"Count: ${snapshot.get(AggregateField.count())}")Log.d(TAG,"Sum: ${snapshot.get(AggregateField.sum("population"))}")Log.d(TAG,"Average: ${snapshot.get(AggregateField.average("population"))}")}else{Log.d(TAG,"Aggregate failed: ",task.getException())}}

Dart

db.collection("cities").aggregate(count(),sum("population"),average("population"),).get().then((res){print(res.count);print(res.getSum("population"));print(res.getAverage("population"));},onError:(e)=>print("Error completing: $e"),);
Java
collection=db.collection("cities");query=collection.whereEqualTo("state","CA");AggregateQueryaggregateQuery=query.aggregate(count(),sum("population"),average("population"));snapshot=aggregateQuery.get().get();System.out.println("Count: "+snapshot.getCount());System.out.println("Sum: "+snapshot.get(sum("population")));System.out.println("Average: "+snapshot.get(average("population")));
Node.js
constcoll=firestore.collection('cities');constaggregateQuery=coll.aggregate({countOfDocs:AggregateField.count(),totalPopulation:AggregateField.sum('population'),averagePopulation:AggregateField.average('population')});constsnapshot=awaitaggregateQuery.get();console.log('countOfDocs: ',snapshot.data().countOfDocs);console.log('totalPopulation: ',snapshot.data().totalPopulation);console.log('averagePopulation: ',snapshot.data().averagePopulation);
Python
collection_ref=client.collection("users")query=collection_ref.where(filter=FieldFilter("people","==","Matthew"))aggregate_query=aggregation.AggregationQuery(query)aggregate_query.sum("coins",alias="sum").avg("coins",alias="avg")results=aggregate_query.get()forresultinresults:print(f"Alias of results from query: {result[0].alias}")print(f"Aggregation of results from query: {result[0].value}")
Go
funccreateMultiAggregationQuery(wio.Writer,projectIDstring)error{ctx:=context.Background()client,err:=firestore.NewClient(ctx,projectID)iferr!=nil{returnerr}deferclient.Close()collection:=client.Collection("users")query:=collection.Where("born",">",1850)aggregationQuery:=query.NewAggregationQuery().WithCount("count").WithSum("coins","sum_coins").WithAvg("coins","avg_coins")results,err:=aggregationQuery.Get(ctx)iferr!=nil{returnerr}}

Queries with multiple aggregations include only the documents that contain all the fields in each aggregation. This might lead to different results from performing each aggregation separately.

Security rules for aggregation queries

Cloud Firestore Security Rules work the same on aggregation queries as on queries that return documents. In other words, if and only if your rules allow clients to execute certain collection or collection group queries, clients can also perform the aggregation on those queries. Learn more about how Cloud Firestore Security Rules interact with queries.

Behavior and limitations

As you work with aggregation queries, note the following behavior and limitations:

  • You can't use aggregation queries with real-time listeners and offline queries. Aggregation queries are only supported through a direct server response. Queries are served only by the Cloud Firestore backend, skipping the local cache and any buffered updates. This behavior is identical to operations that are performed insideCloud Firestore transactions.

  • If an aggregation can't resolve within 60 seconds, it returns a DEADLINE_EXCEEDED error. Performance depends on your index configuration and on the size of the dataset.

    If the operation can't be completed within the 60 second deadline, a possible workaround is to use counters for large datasets.

  • Aggregation queries read from index entries and include only indexed fields.

  • Adding an OrderBy clause to an aggregation query limits the aggregation to the documents where the sorting field exists.

  • For sum() and average() aggregations, non-numeric values are ignored. sum() and average() aggregations take into account only integer values and floating-point number values.

  • When combining multiple aggregations in a single query, note that sum() and average() ignore non-numeric values while count() includes non-numeric values.

  • If you combine aggregations that are on different fields, the calculation includes only the documents that contain all those fields.

Pricing

Pricing for aggregation queries depends on the number of index entries that the query matches. You are charged a small number of reads for a large number of matched entries. You are charged one read operation for each batch of up to 1000 index entries read.

For more information about aggregation queries pricing, see Aggregation queries.