Агрегирующий запрос обрабатывает данные из нескольких записей индекса, чтобы вернуть одно сводное значение.
Cloud Firestore поддерживает следующие запросы агрегации:
-
count()
-
sum()
-
average()
Cloud Firestore вычисляет агрегирование и передает в ваше приложение только результат. По сравнению с выполнением полного запроса и вычислением агрегирования в вашем приложении, запросы агрегирования экономят как на чтении оплачиваемых документов, так и на передаваемых байтах.
Запросы агрегации полагаются на существующую конфигурацию индекса, которую уже используют ваши запросы, и масштабируются пропорционально количеству сканируемых записей индекса. Задержка увеличивается с увеличением количества элементов в агрегации.
Используйте агрегацию count()
Агрегирующий запрос count()
позволяет определить количество документов в коллекции или запросе.
Обратитесь к примеру данных, которые мы настроили в разделе Получение данных .
Следующая агрегация count()
возвращает общее количество городов в коллекции cities
.
Web modular API
const coll = collection(db, "cities"); const snapshot = await getCountFromServer(coll); console.log('count: ', snapshot.data().count);
Быстрый
let query = db.collection("cities") let countQuery = query.count do { let snapshot = try await countQuery.getAggregation(source: .server) print(snapshot.count) } catch { print(error) }
Цель-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"), );
Идти
Джава
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);
Питон
Агрегация count()
учитывает любые фильтры запроса и любые limit
.
Web modular API
const coll = collection(db, "cities"); const q = query(coll, where("state", "==", "CA")); const snapshot = await getCountFromServer(q); console.log('count: ', snapshot.data().count);
Быстрый
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) }
Цель-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"), );
Идти
Джава
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);
Питон
Используйте агрегацию sum()
Используйте агрегацию sum()
для возврата общей суммы числовых значений, соответствующих заданному запросу, например:
Web modular API
const coll = collection(firestore, 'cities'); const snapshot = await getAggregateFromServer(coll, { totalPopulation: sum('population') }); console.log('totalPopulation: ', snapshot.data().totalPopulation);
Джава
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);
Агрегация sum()
учитывает любые фильтры запроса и любые ограничения, например:
Web modular API
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);
Джава
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);
Используйте агрегацию average()
Используйте агрегацию average()
для возврата среднего числовых значений, соответствующих заданному запросу, например:
Web modular API
const coll = collection(firestore, 'cities'); const snapshot = await getAggregateFromServer(coll, { averagePopulation: average('population') }); console.log('averagePopulation: ', snapshot.data().averagePopulation);
Джава
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);
Агрегация average()
учитывает любые фильтры запроса и любые ограничения, например:
Web modular API
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);
Джава
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);
Вычисление нескольких агрегатов в запросе
Вы можете объединить несколько агрегаций в один конвейер агрегации. Это может уменьшить количество необходимых операций чтения индекса. Если запрос включает агрегаты по нескольким полям, для него может потребоваться составной индекс. В этом случае Cloud Firestore предлагает индекс.
В следующем примере выполняется несколько агрегаций в одном запросе агрегации:
Web modular API
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);
Джава
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);
Запросы с несколькими агрегатами включают только те документы, которые содержат все поля в каждом агрегате. Это может привести к различным результатам при выполнении каждого агрегирования по отдельности.
Правила безопасности для запросов агрегирования
Правила безопасности Cloud Firestore работают с запросами агрегации так же, как и с запросами, возвращающими документы. Другими словами, если и только если ваши правила позволяют клиентам выполнять определенные запросы к коллекциям или группам коллекций, клиенты также могут выполнять агрегацию по этим запросам. Узнайте больше о том , как правила безопасности Cloud Firestore взаимодействуют с запросами .
Поведение и ограничения
При работе с запросами агрегирования обратите внимание на следующее поведение и ограничения:
Вы не можете использовать запросы агрегации с прослушивателями в реальном времени и автономными запросами. Запросы агрегации поддерживаются только посредством прямого ответа сервера. Запросы обслуживаются только серверной частью Cloud Firestore, минуя локальный кеш и любые буферизованные обновления. Это поведение идентично операциям, выполняемым внутри транзакций Cloud Firestore .
Если агрегация не может быть решена в течение 60 секунд, она возвращает ошибку
DEADLINE_EXCEEDED
. Производительность зависит от конфигурации индекса и размера набора данных.Если операция не может быть завершена в течение 60 секунд, возможным решением является использование счетчиков для больших наборов данных.
Запросы агрегирования считывают записи индекса и включают только индексированные поля.
Добавление предложения
OrderBy
в запрос агрегации ограничивает агрегацию документами, в которых существует поле сортировки.Для агрегатов
sum()
иaverage()
нечисловые значения игнорируются. Агрегацииsum()
иaverage()
учитывают только целочисленные значения и значения чисел с плавающей запятой.При объединении нескольких агрегатов в одном запросе обратите внимание, что
sum()
иaverage()
игнорируют нечисловые значения, аcount()
включает нечисловые значения.Если вы объединяете агрегаты, находящиеся в разных полях, в расчет включаются только документы, содержащие все эти поля.
Цены
Стоимость запросов агрегирования зависит от количества записей индекса, соответствующих запросу. С вас взимается небольшая плата за чтение за большое количество совпадающих записей.
См. более подробную информацию о ценах .