Resuma dados com consultas de agregação

Uma consulta de agregação processa os dados de diversas entradas de índice para retornar um único valor de resumo.

O Cloud Firestore oferece suporte às seguintes consultas de agregação:

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

O Cloud Firestore calcula a agregação e transmite apenas o resultado para seu aplicativo. Em comparação com a execução de uma consulta completa e o cálculo da agregação em seu aplicativo, as consultas de agregação economizam nas leituras de documentos faturados e nos bytes transferidos.

As consultas de agregação dependem da configuração de índice existente que suas consultas já usam e são dimensionadas proporcionalmente ao número de entradas de índice verificadas. A latência aumenta com o número de itens na agregação.

Use a agregação count()

A consulta de agregação count() permite determinar o número de documentos em uma coleção ou consulta.

Consulte os dados de exemplo que configuramos em Obtendo dados .

A seguinte agregação count() retorna o número total de cidades na coleção cities .

const coll = collection(db, "cities");
const snapshot = await getCountFromServer(coll);
console
.log('count: ', snapshot.data().count);
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities")
let countQuery = query.count
do {
 
let snapshot = try await countQuery.getAggregation(source: .server)
  print
(snapshot.count)
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRCollectionReference *query = [self.db collectionWithPath:@"cities"];
[query.count aggregationWithSource:FIRAggregateSourceServer
                        completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                     
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching count: %@", error);
   
} else {
       
NSLog(@"Cities count: %@", snapshot.count);
   
}
}];
Query query = db.collection("cities");
AggregateQuery countQuery = query.count();
countQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Count fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Count: " + snapshot.getCount());
       
} else {
           
Log.d(TAG, "Count failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities")
val countQuery = query.count()
countQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Count fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Count: ${snapshot.count}")
   
} else {
       
Log.d(TAG, "Count failed: ", task.getException())
   
}
}
// Returns number of documents in users collection
db
.collection("users").count().get().then(
     
(res) => print(res.count),
      onError
: (e) => print("Error completing: $e"),
   
);
package firestore

import (
       
"context"
       
"errors"
       
"fmt"
       
"io"

       
"cloud.google.com/go/firestore"
        firestorepb
"cloud.google.com/go/firestore/apiv1/firestorepb"
)

func createCountQuery
(w io.Writer, projectID string) error {

       
// Instantiate the client
        ctx
:= context.Background()
        client
, err := firestore.NewClient(ctx, projectID)
       
if err != nil {
               
return err
       
}
        defer client
.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)
       
if err != nil {
               
return err
       
}

        count
, ok := results["all"]
       
if !ok {
               
return errors.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())
       
return nil
}
CollectionReference collection = db.collection("cities");
AggregateQuerySnapshot snapshot = collection.count().get().get();
System.out.println("Count: " + snapshot.getCount());
     
const collectionRef = db.collection('cities');
const snapshot = await collectionRef.count().get();
console
.log(snapshot.data().count);
     
from google.cloud import firestore
from google.cloud.firestore_v1 import aggregation
from google.cloud.firestore_v1.base_query import FieldFilter


def create_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 results
    aggregate_query
.count(alias="all")

    results
= aggregate_query.get()
   
for result in results:
       
print(f"Alias of results from query: {result[0].alias}")
       
print(f"Number of results from query: {result[0].value}")

A agregação count() leva em consideração quaisquer filtros na consulta e quaisquer cláusulas limit .

const coll = collection(db, "cities");
const q = query(coll, where("state", "==", "CA"));
const snapshot = await getCountFromServer(q);
console
.log('count: ', snapshot.data().count);
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities").whereField("state", isEqualTo: "CA")
let countQuery = query.count
do {
 
let snapshot = try await countQuery.getAggregation(source: .server)
  print
(snapshot.count)
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query =
   
[[self.db collectionWithPath:@"cities"]
                 queryWhereField
:@"state"
                       isEqualTo
:@"CA"];
[query.count aggregationWithSource:FIRAggregateSourceServer
                        completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                     
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching count: %@", error);
   
} else {
       
NSLog(@"Cities count: %@", snapshot.count);
   
}
}];
Query query = db.collection("cities").whereEqualTo("state", "CA");
AggregateQuery countQuery = query.count();
countQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Count fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Count: " + snapshot.getCount());
       
} else {
           
Log.d(TAG, "Count failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities").whereEqualTo("state", "CA")
val countQuery = query.count()
countQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Count fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Count: ${snapshot.count}")
   
} else {
       
Log.d(TAG, "Count failed: ", task.getException())
   
}
}
// This also works with collectionGroup queries.
db
.collection("users").where("age", isGreaterThan: 10).count().get().then(
     
(res) => print(res.count),
      onError
: (e) => print("Error completing: $e"),
   
);
package firestore

import (
       
"context"
       
"errors"
       
"fmt"
       
"io"

       
"cloud.google.com/go/firestore"
        firestorepb
"cloud.google.com/go/firestore/apiv1/firestorepb"
)

func createCountQuery
(w io.Writer, projectID string) error {

       
// Instantiate the client
        ctx
:= context.Background()
        client
, err := firestore.NewClient(ctx, projectID)
       
if err != nil {
               
return err
       
}
        defer client
.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)
       
if err != nil {
               
return err
       
}

        count
, ok := results["all"]
       
if !ok {
               
return errors.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())
       
return nil
}
CollectionReference collection = db.collection("cities");
Query query = collection.whereEqualTo("state", "CA");
AggregateQuerySnapshot snapshot = query.count().get().get();
System.out.println("Count: " + snapshot.getCount());
     
const collectionRef = db.collection('cities');
const query = collectionRef.where('state', '==', 'CA');
const snapshot = await query.count().get();
console
.log(snapshot.data().count);
     
from google.cloud import firestore
from google.cloud.firestore_v1 import aggregation
from google.cloud.firestore_v1.base_query import FieldFilter


def create_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 results
    aggregate_query
.count(alias="all")

    results
= aggregate_query.get()
   
for result in results:
       
print(f"Alias of results from query: {result[0].alias}")
       
print(f"Number of results from query: {result[0].value}")

Use a agregação sum()

Use a agregação sum() para retornar a soma total dos valores numéricos que correspondem a uma determinada consulta — por exemplo:

const coll = collection(firestore, 'cities');
const snapshot = await getAggregateFromServer(coll, {
  totalPopulation
: sum('population')
});

console
.log('totalPopulation: ', snapshot.data().totalPopulation);
   
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities")
let aggregateQuery = query.aggregate([AggregateField.sum("population")])
do {
 
let snapshot = try await aggregateQuery.getAggregation(source: .server)
  print
(snapshot.get(AggregateField.sum("population")))
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query = [self.db collectionWithPath:@"cities"];
FIRAggregateQuery *aggregateQuery = [query aggregate:@[
   
[FIRAggregateField aggregateFieldForSumOfField:@"population"]]];
[aggregateQuery aggregationWithSource:FIRAggregateSourceServer
                           completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                       
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching aggregate: %@", error);
   
} else {
       
NSLog(@"Sum: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"population"]]);
   
}
}];
Query query = db.collection("cities");
AggregateQuery aggregateQuery = query.aggregate(AggregateField.sum("population"));
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Aggregate fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Sum: " + snapshot.get(AggregateField.sum("population")));
       
} else {
           
Log.d(TAG, "Aggregation failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities")
val aggregateQuery = query.aggregate(AggregateField.sum("population"))
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Aggregate fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Sum: ${snapshot.get(AggregateField.sum("population"))}")
   
} else {
       
Log.d(TAG, "Aggregate failed: ", task.getException())
   
}
}
collection = db.collection("cities");
snapshot
= collection.aggregate(sum("population")).get().get();
System.out.println("Sum: " + snapshot.get(sum("population")));
     
const coll = firestore.collection('cities');
const sumAggregateQuery = coll.aggregate({
         totalPopulation
: AggregateField.sum('population'),
       
});
 
const snapshot = await sumAggregateQuery.get();
console
.log('totalPopulation: ', snapshot.data().totalPopulation);
     
collection_ref = client.collection("users")
aggregate_query
= aggregation.AggregationQuery(collection_ref)

aggregate_query
.sum("coins", alias="sum")

results
= aggregate_query.get()
for result in results:
    print
(f"Alias of results from query: {result[0].alias}")
    print
(f"Sum of results from query: {result[0].value}")
     
func createSumQuery(w io.Writer, projectID string) error {
  ctx
:= context.Background()
  client
, err := firestore.NewClient(ctx, projectID)
 
if err != nil {
   
return err
 
}
  defer client
.Close()

  collection
:= client.Collection("users")
  query
:= collection.Where("born", ">", 1850)

  aggregationQuery
:= query.NewAggregationQuery().WithSum("coins", "sum_coins")
  results
, err := aggregationQuery.Get(ctx)
 
if err != nil {
   
return err
 
}

  sum
, ok := results["sum_coins"]
 
if !ok {
   
return errors.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())
 
return nil
}
     

A agregação sum() leva em consideração quaisquer filtros na consulta e quaisquer cláusulas de limite — por exemplo:

const coll = collection(firestore, 'cities');
const q = query(coll, where('capital', '==', true));
const snapshot = await getAggregateFromServer(q, {
  totalPopulation
: sum('population')
});

console
.log('totalPopulation: ', snapshot.data().totalPopulation);
     
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities").whereField("capital", isEqualTo: true)
let aggregateQuery = query.aggregate([AggregateField.sum("population")])
do {
 
let snapshot = try await aggregateQuery.getAggregation(source: .server)
  print
(snapshot.get(AggregateField.sum("population")))
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query = [[self.db collectionWithPath:@"cities"]
                   queryWhereFilter
:[FIRFilter filterWhereField:@"capital" isEqualTo:@YES]];
FIRAggregateQuery *aggregateQuery = [query aggregate:@[
   
[FIRAggregateField aggregateFieldForSumOfField:@"population"]]];
[aggregateQuery aggregationWithSource:FIRAggregateSourceServer
                           completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                       
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching aggregate: %@", error);
   
} else {
       
NSLog(@"Sum: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"population"]]);
   
}
}];
Query query = db.collection("cities").whereEqualTo("capital", true);
AggregateQuery aggregateQuery = query.aggregate(AggregateField.sum("population"));
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Aggregate fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Sum: " + snapshot.get(AggregateField.sum("population")));
       
} else {
           
Log.d(TAG, "Aggregation failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities").whereEqualTo("capital", true)
val aggregateQuery = query.aggregate(AggregateField.sum("population"))
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Aggregate fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Sum: ${snapshot.get(AggregateField.sum("population"))}")
   
} else {
       
Log.d(TAG, "Aggregate failed: ", task.getException())
   
}
}
collection = db.collection("cities");
query
= collection.whereEqualTo("state", "CA");
snapshot
= query.aggregate(sum("population")).get().get();
System.out.println("Sum: " + snapshot.get(sum("population")));
     
const coll = firestore.collection('cities');
const q = coll.where("capital", "==", true);
const sumAggregateQuery = q.aggregate({
        totalPopulation
: AggregateField.sum('population'),
     
});

const snapshot = await sumAggregateQuery.get();
console
.log('totalPopulation: ', snapshot.data().totalPopulation);
     
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()
for result in results:
    print
(f"Alias of results from query: {result[0].alias}")
    print
(f"Sum of results from query: {result[0].value}")
     
func createSumQuery(w io.Writer, projectID string) error {
  ctx
:= context.Background()
  client
, err := firestore.NewClient(ctx, projectID)
 
if err != nil {
   
return err
 
}
  defer client
.Close()

  collection
:= client.Collection("users")
  query
:= collection.Where("born", ">", 1850).Limit(5)

  aggregationQuery
:= query.NewAggregationQuery().WithSum("coins", "sum_coins")
  results
, err := aggregationQuery.Get(ctx)
 
if err != nil {
   
return err
 
}

  sum
, ok := results["sum_coins"]
 
if !ok {
   
return errors.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())
 
return nil
}
     

Use a agregação average()

Use a agregação average() para retornar a média dos valores numéricos que correspondem a uma determinada consulta — por exemplo:

const coll = collection(firestore, 'cities');
const snapshot = await getAggregateFromServer(coll, {
  averagePopulation
: average('population')
});

console
.log('averagePopulation: ', snapshot.data().averagePopulation);
   
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities")
let aggregateQuery = query.aggregate([AggregateField.average("population")])
do {
 
let snapshot = try await aggregateQuery.getAggregation(source: .server)
  print
(snapshot.get(AggregateField.average("population")))
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query = [self.db collectionWithPath:@"cities"];
FIRAggregateQuery *aggregateQuery = [query aggregate:@[
   
[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]];
[aggregateQuery aggregationWithSource:FIRAggregateSourceServer
                           completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                       
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching aggregate: %@", error);
   
} else {
       
NSLog(@"Avg: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]);
   
}
}];
Query query = db.collection("cities");
AggregateQuery aggregateQuery = query.aggregate(AggregateField.average("population"));
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Aggregate fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Average: " + snapshot.get(AggregateField.average("population")));
       
} else {
           
Log.d(TAG, "Aggregation failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities")
val aggregateQuery = query.aggregate(AggregateField.average("population"))
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Aggregate fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Average: ${snapshot.get(AggregateField.average("population"))}")
   
} else {
       
Log.d(TAG, "Aggregate failed: ", task.getException())
   
}
}
collection = db.collection("cities");
snapshot
= collection.aggregate(average("population")).get().get();
System.out.println("Average: " + snapshot.get(average("population")));
     
const coll = firestore.collection('cities');
const averageAggregateQuery = coll.aggregate({
        averagePopulation
: AggregateField.average('population'),
     
});

const snapshot = await averageAggregateQuery.get();
console
.log('averagePopulation: ', snapshot.data().averagePopulation);
     
collection_ref = client.collection("users")
aggregate_query
= aggregation.AggregationQuery(collection_ref)

aggregate_query
.avg("coins", alias="avg")

results
= aggregate_query.get()
for result in results:
    print
(f"Alias of results from query: {result[0].alias}")
    print
(f"Average of results from query: {result[0].value}")
     
func createAvgQuery(w io.Writer, projectID string) error {
  ctx
:= context.Background()
  client
, err := firestore.NewClient(ctx, projectID)
 
if err != nil {
         
return err
 
}
  defer client
.Close()

  collection
:= client.Collection("users")
  query
:= collection.Where("born", ">", 1850)

  aggregationQuery
:= query.NewAggregationQuery().WithAvg("coins", "avg_coins")
  results
, err := aggregationQuery.Get(ctx)
 
if err != nil {
   
return err
 
}

  avg
, ok := results["avg_coins"]
 
if !ok {
   
return errors.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())
 
return nil
}
     

A agregação average() leva em consideração quaisquer filtros na consulta e quaisquer cláusulas de limite — por exemplo:

const coll = collection(firestore, 'cities');
const q = query(coll, where('capital', '==', true));
const snapshot = await getAggregateFromServer(q, {
  averagePopulation
: average('population')
});

console
.log('averagePopulation: ', snapshot.data().averagePopulation);
     
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities").whereField("capital", isEqualTo: true)
let aggregateQuery = query.aggregate([AggregateField.average("population")])
do {
 
let snapshot = try await aggregateQuery.getAggregation(source: .server)
  print
(snapshot.get(AggregateField.average("population")))
} catch {
  print
(error)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query = [[self.db collectionWithPath:@"cities"]
                   queryWhereFilter
:[FIRFilter filterWhereField:@"capital" isEqualTo:@YES]];
FIRAggregateQuery *aggregateQuery = [query aggregate:@[
   
[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]];
[aggregateQuery aggregationWithSource:FIRAggregateSourceServer
                           completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                       
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching aggregate: %@", error);
   
} else {
       
NSLog(@"Avg: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]);
   
}
}];
Query query = db.collection("cities").whereEqualTo("capital", true);
AggregateQuery aggregateQuery = query.aggregate(AggregateField.average("population"));
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Aggregate fetched successfully
           
AggregateQuerySnapshot snapshot = task.getResult();
           
Log.d(TAG, "Average: " + snapshot.get(AggregateField.average("population")));
       
} else {
           
Log.d(TAG, "Aggregation failed: ", task.getException());
       
}
   
}
});
val query = db.collection("cities").whereEqualTo("capital", true)
val aggregateQuery = query.aggregate(AggregateField.average("population"))
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Aggregate fetched successfully
       
val snapshot = task.result
       
Log.d(TAG, "Average: ${snapshot.get(AggregateField.average("population"))}")
   
} else {
       
Log.d(TAG, "Aggregate failed: ", task.getException())
   
}
}
collection = db.collection("cities");
query
= collection.whereEqualTo("state", "CA");
snapshot
= query.aggregate(average("population")).get().get();
System.out.println("Average: " + snapshot.get(average("population")));
 
const coll = firestore.collection('cities');
const q = coll.where("capital", "==", true);
const averageAggregateQuery = q.aggregate({
        averagePopulation
: AggregateField.average('population'),
     
});

const snapshot = await averageAggregateQuery.get();
console
.log('averagePopulation: ', snapshot.data().averagePopulation);
     
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()
for result in results:
    print
(f"Alias of results from query: {result[0].alias}")
    print
(f"Average of results from query: {result[0].value}")
     
func createAvgQuery(w io.Writer, projectID string) error {
  ctx
:= context.Background()
  client
, err := firestore.NewClient(ctx, projectID)
 
if err != nil {
       
return err
 
}
  defer client
.Close()

  collection
:= client.Collection("users")
  query
:= collection.Where("born", ">", 1850).Limit(5)

  aggregationQuery
:= query.NewAggregationQuery().WithAvg("coins", "avg_coins")
  results
, err := aggregationQuery.Get(ctx)
 
if err != nil {
   
return err
 
}

  avg
, ok := results["avg_coins"]
 
if !ok {
   
return errors.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())
 
return nil
}
     

Calcular múltiplas agregações em uma consulta

Você pode combinar diversas agregações em um único pipeline de agregação. Isso pode reduzir o número de leituras de índice necessárias. Se a consulta incluir agregações em vários campos, a consulta poderá exigir um índice composto. Nesse caso, o Cloud Firestore sugere um índice.

O exemplo a seguir executa diversas agregações em uma única consulta de agregação:

const coll = collection(firestore, 'cities');
const snapshot = await getAggregateFromServer(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);
     
Observação: este produto não está disponível em destinos watchOS e App Clip.
let query = db.collection("cities")
let aggregateQuery = query.aggregate([
 
AggregateField.count(),
 
AggregateField.sum("population"),
 
AggregateField.average("population")])
do {
 
let snapshot = try await aggregateQuery.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)
}
Observação: este produto não está disponível em destinos watchOS e App Clip.
FIRQuery *query = [self.db collectionWithPath:@"cities"];
FIRAggregateQuery *aggregateQuery = [query aggregate:@[
   
[FIRAggregateField aggregateFieldForCount],
   
[FIRAggregateField aggregateFieldForSumOfField:@"population"],
   
[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]];
[aggregateQuery aggregationWithSource:FIRAggregateSourceServer
                           completion
:^(FIRAggregateQuerySnapshot *snapshot,
                                       
NSError *error) {
   
if (error != nil) {
       
NSLog(@"Error fetching aggregate: %@", error);
   
} else {
       
NSLog(@"Count: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]]);
       
NSLog(@"Sum: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"population"]]);
       
NSLog(@"Avg: %@", [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForAverageOfField:@"population"]]);
   
}
}];
Query query = db.collection("cities");
AggregateQuery aggregateQuery = query.aggregate(
       
AggregateField.count(),
       
AggregateField.sum("population"),
       
AggregateField.average("population"));
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener(new OnCompleteListener<AggregateQuerySnapshot>() {
   
@Override
   
public void onComplete(@NonNull Task<AggregateQuerySnapshot> task) {
       
if (task.isSuccessful()) {
           
// Aggregate fetched successfully
           
AggregateQuerySnapshot snapshot = 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());
       
}
   
}
});
val query = db.collection("cities")
val aggregateQuery = query.aggregate(
   
AggregateField.count(),
   
AggregateField.sum("population"),
   
AggregateField.average("population")
)
aggregateQuery
.get(AggregateSource.SERVER).addOnCompleteListener { task ->
   
if (task.isSuccessful) {
       
// Aggregate fetched successfully
       
val snapshot = task.result
       
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, "Aggregate failed: ", task.getException())
   
}
}
collection = db.collection("cities");
query
= collection.whereEqualTo("state", "CA");
AggregateQuery aggregateQuery = 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")));
   
const coll = firestore.collection('cities');
const aggregateQuery = coll.aggregate({
    countOfDocs
: AggregateField.count(),
    totalPopulation
: AggregateField.sum('population'),
    averagePopulation
: AggregateField.average('population')
 
});

const snapshot = await aggregateQuery.get();
console
.log('countOfDocs: ', snapshot.data().countOfDocs);
console
.log('totalPopulation: ', snapshot.data().totalPopulation);
console
.log('averagePopulation: ', snapshot.data().averagePopulation);
     
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()
for result in results:
    print
(f"Alias of results from query: {result[0].alias}")
    print
(f"Aggregation of results from query: {result[0].value}")
     
func createMultiAggregationQuery(w io.Writer, projectID string) error {
  ctx
:= context.Background()
  client
, err := firestore.NewClient(ctx, projectID)
 
if err != nil {
   
return err
 
}
  defer client
.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)
 
if err != nil {
   
return err
 
}
}
     

As consultas com múltiplas agregações incluem apenas os documentos que contêm todos os campos em cada agregação. Isso pode levar a resultados diferentes ao realizar cada agregação separadamente.

Regras de segurança para consultas de agregação

As regras de segurança do Cloud Firestore funcionam da mesma forma em consultas de agregação e em consultas que retornam documentos. Em outras palavras, se e somente se suas regras permitirem que os clientes executem determinadas consultas de coleção ou de grupo de coleções, os clientes também poderão realizar a agregação nessas consultas. Saiba mais sobre como as regras de segurança do Cloud Firestore interagem com as consultas .

Comportamento e limitações

Ao trabalhar com consultas de agregação, observe o seguinte comportamento e limitações:

  • Não é possível usar consultas de agregação com listeners em tempo real e consultas offline. As consultas de agregação só são suportadas por meio de resposta direta do servidor. As consultas são atendidas apenas pelo back-end do Cloud Firestore, ignorando o cache local e quaisquer atualizações em buffer. Esse comportamento é idêntico às operações realizadas nas transações do Cloud Firestore .

  • Se uma agregação não puder ser resolvida em 60 segundos, ela retornará um erro DEADLINE_EXCEEDED . O desempenho depende da configuração do seu índice e do tamanho do conjunto de dados.

    Se a operação não puder ser concluída dentro do prazo de 60 segundos, uma solução possível é usar contadores para grandes conjuntos de dados.

  • As consultas de agregação são lidas a partir de entradas de índice e incluem apenas campos indexados.

  • Adicionar uma cláusula OrderBy a uma consulta de agregação limita a agregação aos documentos onde existe o campo de classificação.

  • Para agregações sum() e average() , os valores não numéricos são ignorados. As agregações sum() e average() levam em consideração apenas valores inteiros e valores numéricos de ponto flutuante.

  • Ao combinar múltiplas agregações em uma única consulta, observe que sum() e average() ignoram valores não numéricos, enquanto count() inclui valores não numéricos.

  • Se você combinar agregações que estão em campos diferentes, o cálculo incluirá apenas os documentos que contêm todos esses campos.

Preços

O preço das consultas de agregações depende do número de entradas de índice correspondentes à consulta. É cobrado um pequeno número de leituras para um grande número de entradas correspondentes.

Veja informações mais detalhadas sobre preços .