Zählen Sie Dokumente mit Aggregationsabfragen

Eine Aggregationsabfrage verarbeitet die Daten aus mehreren Indexeinträgen, um einen einzelnen Zusammenfassungswert zurückzugeben.

Cloud Firestore unterstützt die Aggregationsabfrage count() . count() können Sie die Anzahl der Dokumente in einer Sammlung oder Abfrage ermitteln. Der Server berechnet die Anzahl und überträgt nur das Ergebnis, eine einzelne Ganzzahl, zurück an Ihre App. Dadurch werden im Vergleich zur Ausführung der vollständigen Abfrage sowohl Lesevorgänge für abgerechnete Dokumente als auch übertragene Bytes eingespart.

Aggregationsabfragen basieren auf der vorhandenen Indexkonfiguration, die Ihre Abfragen bereits verwenden, und skalieren proportional zur Anzahl der gescannten Indexeinträge. Dies bedeutet, dass Aggregationen kleiner bis mittelgroßer Datensätze innerhalb von 20–40 ms ausgeführt werden, obwohl die Latenz mit der Anzahl der gezählten Elemente zunimmt.

Verwenden Sie die count() -Aggregation

Sehen Sie sich die Beispieldaten an, die wir unter „Daten abrufen“ eingerichtet haben.

Die folgende count() -Aggregation gibt die Gesamtzahl der Städte in der cities zurück.

Web modular API

const coll = collection(db, "cities");
const snapshot = await getCountFromServer(coll);
console.log('count: ', snapshot.data().count);
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
let query = db.collection("cities")
let countQuery = query.count
do {
    let snapshot = try await countQuery.getAggregation(source: .server)
    print(snapshot.count)
} catch {
    print(error)
}
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
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"),
    );
Gehen
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
}
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
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}")

Die count() Aggregation berücksichtigt alle Filter der Abfrage und alle 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);
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
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)
}
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
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"),
    );
Gehen
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
}
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
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}")

Cloud Firestore-Sicherheitsregeln funktionieren bei count() -Aggregationsabfragen genauso wie bei normalen Abfragen, die Dokumente zurückgeben. Mit anderen Worten: Nur wenn Ihre Regeln es Clients erlauben, bestimmte Sammlungs- oder Sammlungsgruppenabfragen auszuführen, können Clients auch die count() Aggregation für diese Abfragen durchführen. Erfahren Sie mehr darüber, wie Cloud Firestore-Sicherheitsregeln mit Abfragen interagieren .

Einschränkungen

Beachten Sie die folgenden Einschränkungen für die Aggregationsabfrage count() :

  • count() Aggregationsabfragen werden derzeit nur über direkte Serverantworten unterstützt. Abfragen werden nur vom Cloud Firestore-Backend bedient, wobei der lokale Cache und alle gepufferten Aktualisierungen übersprungen werden. Dieses Verhalten ist identisch mit Vorgängen, die innerhalb von Cloud Firestore-Transaktionen ausgeführt werden. Sie können count() Abfragen derzeit nicht mit Echtzeit-Listenern und Offline-Abfragen verwenden.

  • Wenn eine count() Aggregation nicht innerhalb von 60 Sekunden aufgelöst werden kann, wird der Fehler DEADLINE_EXCEEDED zurückgegeben. Die Leistung hängt von Ihrer Indexkonfiguration und der Größe des Datensatzes ab.

    Wenn der Vorgang nicht innerhalb der Frist von 60 Sekunden abgeschlossen werden kann, besteht eine mögliche Problemumgehung darin, Zähler für große Datensätze zu verwenden.

  • Die count() -Aggregation liest aus Indexeinträgen und zählt nur indizierte Felder.

  • Durch das Hinzufügen einer OrderBy Klausel zur Abfrage wird die Anzahl auf die Dokumente beschränkt, in denen das Sortierfeld vorhanden ist.

Preisgestaltung

Der Preis für count() hängt von der Anzahl der Indexeinträge ab, die mit der Abfrage übereinstimmen. Für eine große Anzahl übereinstimmender Einträge wird Ihnen eine geringe Anzahl an Lesevorgängen berechnet.

Weitere detaillierte Preisinformationen finden Sie hier.