Summarize data with aggregation queries

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

Cloud Firestore supports the followingaggregation queries:

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

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

Aggregation queries rely on the existing index configuration thatyour queries already use, and scale proportionally to the number of indexentries scanned. Latency increases with the number of itemsin the aggregation.

Note: While the code samples cover multiple languages, the text explaining thesamples refers to the Web method names.

Use thecount() aggregation

Thecount() aggregation query lets youdetermine the number of documents in a collection or query.

For more information about the example data, seeGetting data.

The followingcount() aggregation returns the total number of cities in thecities collection.

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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}")

Thecount() aggregation takes into account any filters on the query and anylimit clauses.

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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 thesum() aggregation

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

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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}

Thesum() aggregation takes into account any filters on the query and anylimit clauses—for example:

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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 theaverage() aggregation

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

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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}

Theaverage() aggregation takes into account any filters on the query and any limitclauses, for example:

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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 canreduce the number of index reads required. If the query includes aggregations onmultiple 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

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
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 allthe fields in each aggregation. This might lead to different results fromperforming each aggregation separately.

Security rules for aggregation queries

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

Behavior and limitations

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

Pricing

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

For more information about aggregation queries pricing, seeAggregation queries.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-10-10 UTC.