Una consulta de agregación procesa los datos de varias entradas de índice para mostrar un solo valor de resumen.
Cloud Firestore admite las siguientes consultas de agregación:
count()
sum()
average()
Cloud Firestore calcula la agregación y transmite solo el resultado a tu app. En comparación con ejecutar una consulta completa y calcular la agregación en tu app, este tipo de consultas ahorran tanto en operaciones de lectura de documentos facturados como en bytes transferidos.
Las consultas de agregación se basan en la configuración de índices existente que tus consultas ya utilizan, y escalan proporcionalmente a la cantidad de entradas de índice analizadas. La latencia aumenta con la cantidad de elementos de la agregación.
Usa la agregación count()
La consulta de agregación count()
te permite determinar la cantidad de documentos en una colección o consulta.
Consulta los datos de ejemplo que configuramos en Cómo obtener datos.
La siguiente agregación count()
muestra la cantidad total de ciudades en la colección cities
.
API modular web
const coll = collection(db, "cities"); const snapshot = await getCountFromServer(coll); console.log('count: ', snapshot.data().count);
Swift
let query = db.collection("cities") let countQuery = query.count do { let snapshot = try await countQuery.getAggregation(source: .server) print(snapshot.count) } catch { print(error) }
Objective‑C
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); } }];
Java
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()); } } });
Kotlin+KTX
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()) } }
Dart
// Returns number of documents in users collection db.collection("users").count().get().then( (res) => print(res.count), onError: (e) => print("Error completing: $e"), );
Go
Java
CollectionReference collection = db.collection("cities"); AggregateQuerySnapshot snapshot = collection.count().get().get(); System.out.println("Count: " + snapshot.getCount());
Node.js
const collectionRef = db.collection('cities'); const snapshot = await collectionRef.count().get(); console.log(snapshot.data().count);
Python
La agregación count()
toma en cuenta cualquier filtro en la consulta y cualquier
cláusula limit
.
API modular web
const coll = collection(db, "cities"); const q = query(coll, where("state", "==", "CA")); const snapshot = await getCountFromServer(q); console.log('count: ', snapshot.data().count);
Swift
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) }
Objective‑C
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); } }];
Java
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()); } } });
Kotlin+KTX
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()) } }
Dart
// 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"), );
Go
Java
CollectionReference collection = db.collection("cities"); Query query = collection.whereEqualTo("state", "CA"); AggregateQuerySnapshot snapshot = query.count().get().get(); System.out.println("Count: " + snapshot.getCount());
Node.js
const collectionRef = db.collection('cities'); const query = collectionRef.where('state', '==', 'CA'); const snapshot = await query.count().get(); console.log(snapshot.data().count);
Python
Usa la agregación sum()
Usa la agregación sum()
para mostrar la suma total de los valores numéricos que coinciden con una consulta determinada, por ejemplo:
API modular web
const coll = collection(firestore, 'cities'); const snapshot = await getAggregateFromServer(coll, { totalPopulation: sum('population') }); console.log('totalPopulation: ', snapshot.data().totalPopulation);
Java
collection = db.collection("cities"); snapshot = collection.aggregate(sum("population")).get().get(); System.out.println("Sum: " + snapshot.get(sum("population")));
Node.js
const coll = firestore.collection('cities'); const sumAggregateQuery = coll.aggregate({ totalPopulation: AggregateField.sum('population'), }); const snapshot = await sumAggregateQuery.get(); console.log('totalPopulation: ', snapshot.data().totalPopulation);
La agregación sum()
tiene en cuenta cualquier filtro en la consulta y cualquier cláusula de límite, por ejemplo:
API modular web
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);
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
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);
Usa la agregación average()
Usa la agregación average()
para mostrar el promedio de valores numéricos que coinciden con una consulta determinada, por ejemplo:
API modular web
const coll = collection(firestore, 'cities'); const snapshot = await getAggregateFromServer(coll, { averagePopulation: average('population') }); console.log('averagePopulation: ', snapshot.data().averagePopulation);
Java
collection = db.collection("cities"); snapshot = collection.aggregate(average("population")).get().get(); System.out.println("Average: " + snapshot.get(average("population")));
Node.js
const coll = firestore.collection('cities'); const averageAggregateQuery = coll.aggregate({ averagePopulation: AggregateField.average('population'), }); const snapshot = await averageAggregateQuery.get(); console.log('averagePopulation: ', snapshot.data().averagePopulation);
La agregación average()
tiene en cuenta cualquier filtro en la consulta y cualquier cláusula de límite, por ejemplo:
API modular web
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);
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
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);
Calcula varias agregaciones en una consulta
Puedes combinar varias agregaciones en una sola canalización de agregación. Esto puede reducir la cantidad de lecturas de índice necesarias. Si la consulta incluye agregaciones en varios campos, puede requerir un índice compuesto. En ese caso, Cloud Firestore sugiere un índice.
En el siguiente ejemplo, se realizan varias agregaciones en una sola consulta de agregación:
API modular web
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);
Java
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")));
Node.js
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);
Las consultas con agregaciones múltiples incluyen solo los documentos que contienen todos los campos de cada agregación. Esto puede generar resultados diferentes a partir de la realización de cada agregación por separado.
Reglas de seguridad para consultas de agregación
Las reglas de seguridad de Cloud Firestore funcionan de la misma manera en las consultas de agregación que en las consultas que muestran documentos. En otras palabras, solo si tus reglas permiten que los clientes ejecuten determinadas consultas de colecciones o grupos de colecciones, los clientes también pueden realizar la agregación en esas consultas. Obtén más información sobre cómo las reglas de seguridad de Cloud Firestore interactúan con las consultas.
Comportamiento y limitaciones
Cuando trabajes con consultas de agregación, ten en cuenta el comportamiento y las limitaciones siguientes:
No puedes usar consultas de agregación con objetos de escucha en tiempo real ni consultas sin conexión. Las consultas de agregación solo se admiten a través de la respuesta directa del servidor. El backend de Cloud Firestore entrega solo consultas que omiten la caché local y las actualizaciones almacenadas en búfer. Este comportamiento es idéntico a las operaciones realizadas dentro de las transacciones de Cloud Firestore.
Si una agregación no se puede resolver en 60 segundos, muestra un error
DEADLINE_EXCEEDED
. El rendimiento depende de la configuración de tu índice y del tamaño del conjunto de datos.Si la operación no se puede completar dentro del plazo de 60 segundos, una solución alternativa es usar contadores para conjuntos de datos grandes.
Las consultas de agregación leen de las entradas de índice y solo incluyen campos indexados.
Agregar una cláusula
OrderBy
a una consulta de agregación limita la agregación a los documentos en los que existe el campo de ordenamiento.Para las agregaciones
sum()
yaverage()
, se ignoran los valores no numéricos. Las agregacionessum()
yaverage()
solo tienen en cuenta los valores de número entero y los de número de punto flotante.Cuando combines varias agregaciones en una sola consulta, ten en cuenta que
sum()
yaverage()
ignoran los valores no numéricos, mientras quecount()
incluye valores no numéricos.Si combinas agregaciones que se encuentran en campos diferentes, el cálculo incluye solo los documentos que contienen todos esos campos.
Precios
El precio de las consultas de agregación depende de la cantidad de entradas de índice que coincidan con la consulta. Se te cobra una pequeña cantidad de lecturas por una gran cantidad de entradas coincidentes.
Consulta la información de precios más detallada.