Catch up on highlights from Firebase at Google I/O 2023. Learn more

Подсчет документов с запросами агрегации

Запрос агрегации обрабатывает данные из нескольких записей индекса, чтобы вернуть одно итоговое значение.

Cloud Firestore поддерживает запрос агрегации count() . count() позволяет определить количество документов в коллекции или запросе. Сервер подсчитывает количество и передает только результат, одно целое число, обратно в ваше приложение, экономя как на чтениях оплачиваемых документов, так и на переданных байтах по сравнению с выполнением полного запроса.

Запросы агрегирования основаны на существующей конфигурации индекса, которую уже используют ваши запросы, и масштабируются пропорционально количеству просканированных записей индекса. Это означает, что агрегация наборов данных малого и среднего размера выполняется в течение 20–40 мс, хотя задержка увеличивается с увеличением количества подсчитанных элементов.

Используйте агрегацию count()

Обратитесь к примеру данных, которые мы настроили в Получение данных .

Следующая агрегация count() возвращает общее количество городов в коллекции cities .

Web modular API

const coll = collection(db, "cities");
const snapshot = await getCountFromServer(coll);
console.log('count: ', snapshot.data().count);
Быстрый
Примечание. Этот продукт недоступен для целей watchOS и 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)
}
Цель-C
Примечание. Этот продукт недоступен для целей watchOS и 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);
    }
}];

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 . Например, следующая агрегация возвращает количество городов, в которых state равно CA .

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);
Быстрый
Примечание. Этот продукт недоступен для целей watchOS и 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)
}
Цель-C
Примечание. Этот продукт недоступен для целей watchOS и 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);
    }
}];

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);
      

Правила безопасности Cloud Firestore работают с запросами агрегации count() так же, как и с обычными запросами, возвращающими документы. Другими словами, если и только если ваши правила позволяют клиентам выполнять определенные запросы коллекции или группы коллекций, клиенты также могут выполнять агрегацию count() для этих запросов. Узнайте больше о том , как правила безопасности Cloud Firestore взаимодействуют с запросами .

Ограничения

Обратите внимание на следующие ограничения на запрос агрегации count() :

  • Запросы агрегации count() в настоящее время поддерживаются только через прямой ответ сервера. Запросы обслуживаются только серверной частью Cloud Firestore, минуя локальный кеш и любые буферизованные обновления. Это поведение идентично операциям, выполняемым внутри транзакций Cloud Firestore . В настоящее время вы не можете использовать запросы count() с прослушивателями в реальном времени и автономными запросами.

  • Если агрегация count() не может разрешиться в течение 60 секунд, она возвращает ошибку DEADLINE_EXCEEDED . Производительность зависит от конфигурации вашего индекса и размера набора данных.

    Если операция не может быть завершена в течение 60 секунд, возможным обходным путем является использование счетчиков для больших наборов данных.

  • Агрегация count() считывает записи индекса и подсчитывает только проиндексированные поля.

  • Добавление предложения OrderBy в запрос ограничивает количество документов, в которых существует поле сортировки.

Цены

Стоимость count() зависит от количества записей индекса, соответствующих запросу. За большое количество совпадающих записей взимается плата за небольшое количество прочтений.

Смотрите более подробную информацию о ценах .