Tóm tắt dữ liệu bằng các truy vấn tổng hợp

Truy vấn tổng hợp xử lý dữ liệu từ nhiều mục nhập chỉ mục để trả về một giá trị tóm tắt duy nhất.

Cloud Firestore hỗ trợ các truy vấn tổng hợp sau đây:

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

Cloud Firestore tính toán quá trình tổng hợp và chỉ truyền kết quả trở lại ứng dụng của bạn. So với việc thực thi một truy vấn đầy đủ và tính toán mức tổng hợp trong ứng dụng của bạn, truy vấn tổng hợp giúp tiết kiệm cả số lượt đọc tài liệu được tính phí và số byte được chuyển.

Các truy vấn tổng hợp dựa vào cấu hình chỉ mục hiện có mà truy vấn của bạn đã sử dụng và tỷ lệ thuận với số lượng mục nhập chỉ mục được quét. Độ trễ tăng lên theo số lượng mục trong quá trình tổng hợp.

Sử dụng tính năng tổng hợp count()

Truy vấn tổng hợp count() cho phép bạn xác định số lượng tài liệu trong một bộ sưu tập hoặc truy vấn.

Để biết thêm thông tin về dữ liệu mẫu, hãy xem phần Nhận dữ liệu.

Hoạt động tổng hợp count() sau đây trả về tổng số thành phố trong tập hợp cities.

Web

const coll = collection(db, "cities");
const snapshot = await getCountFromServer(coll);
console.log('count: ', snapshot.data().count);
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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

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("cities").count().get().then(
      (res) => print(res.count),
      onError: (e) => print("Error completing: $e"),
    );
Tìm
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}")

Hoạt động tổng hợp count() sẽ tính đến mọi bộ lọc trong truy vấn và mọi mệnh đề limit.

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
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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

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 collection queries.
db.collection("cities").where("capital", isEqualTo: 10).count().get().then(
      (res) => print(res.count),
      onError: (e) => print("Error completing: $e"),
    );
Tìm
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}")

Sử dụng tính năng tổng hợp sum()

Sử dụng phương thức tổng hợp sum() để trả về tổng của các giá trị số khớp với một truy vấn nhất định, ví dụ:

Web

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

console.log('totalPopulation: ', snapshot.data().totalPopulation);
    
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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"]]);
    }
}];

Java

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

Kotlin

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())
    }
}

Dart

db.collection("cities").aggregate(sum("population")).get().then(
      (res) => print(res.getAverage("population")),
      onError: (e) => print("Error completing: $e"),
    );
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);
      
Python
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}")
      
Tìm
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
}
      

Hoạt động tổng hợp sum() sẽ tính đến mọi bộ lọc trên truy vấn và mọi mệnh đề giới hạn, ví dụ:

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);
      
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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"]]);
    }
}];

Java

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

Kotlin

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())
    }
}

Dart

db
    .collection("cities")
    .where("capital", isEqualTo: true)
    .aggregate(sum("population"))
    .get()
    .then(
      (res) => print(res.getAverage("population")),
      onError: (e) => print("Error completing: $e"),
    );
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);
      
Python
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}")
      
Tìm
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
}
      

Sử dụng tính năng tổng hợp average()

Sử dụng hàm tổng hợp average() để trả về giá trị trung bình của các giá trị số khớp với một truy vấn nhất định, ví dụ:

Web

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

console.log('averagePopulation: ', snapshot.data().averagePopulation);
    
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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"]]);
    }
}];

Java

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

Kotlin

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())
    }
}

Dart

db.collection("cities").aggregate(average("population")).get().then(
      (res) => print(res.getAverage("population")),
      onError: (e) => print("Error completing: $e"),
    );
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);
      
Python
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}")
      
Tìm
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
}
      

Hoạt động tổng hợp average() sẽ tính đến mọi bộ lọc trên truy vấn và mọi mệnh đề giới hạn, ví dụ:

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);
      
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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"]]);
    }
}];

Java

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

Kotlin

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())
    }
}

Dart

db
    .collection("cities")
    .where("capital", isEqualTo: true)
    .aggregate(average("population"))
    .get()
    .then(
      (res) => print(res.getAverage("population")),
      onError: (e) => print("Error completing: $e"),
    );
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);
      
Python
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}")
      
Tìm
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
}
      

Tính nhiều giá trị tổng hợp trong một truy vấn

Bạn có thể kết hợp nhiều hoạt động tổng hợp trong một quy trình tổng hợp duy nhất. Điều này có thể làm giảm số lượng chỉ mục cần đọc. Nếu truy vấn bao gồm các phép tổng hợp trên nhiều trường, thì truy vấn có thể yêu cầu một chỉ mục kết hợp. Trong trường hợp đó, Cloud Firestore đề xuất một chỉ mục.

Ví dụ sau đây thực hiện nhiều hoạt động tổng hợp trong một truy vấn tổng hợp duy nhất:

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);
      
Swift
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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)
}
Objective-C
Lưu ý: Sản phẩm này không có trên các mục tiêu watchOS và 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"]]);
  }
}];

Java

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

Kotlin

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())
    }
}

Dart

db
    .collection("cities")
    .aggregate(
      count(),
      sum("population"),
      average("population"),
    )
    .get()
    .then(
  (res) {
    print(res.count);
    print(res.getSum("population"));
    print(res.getAverage("population"));
  },
  onError: (e) => print("Error completing: $e"),
);
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);
      
Python
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}")
      
Tìm
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
  }
}
      

Các truy vấn có nhiều phép tổng hợp chỉ bao gồm những tài liệu chứa tất cả các trường trong mỗi phép tổng hợp. Điều này có thể dẫn đến kết quả khác với việc thực hiện từng phép tổng hợp riêng biệt.

Quy tắc bảo mật cho các truy vấn tổng hợp

Cloud Firestore Security Rules hoạt động giống nhau trên các truy vấn tổng hợp như trên các truy vấn trả về tài liệu. Nói cách khác, nếu và chỉ khi các quy tắc của bạn cho phép máy khách thực thi một số truy vấn nhất định về bộ sưu tập hoặc nhóm bộ sưu tập, thì máy khách cũng có thể thực hiện việc tổng hợp trên các truy vấn đó. Tìm hiểu thêm về cách Cloud Firestore Security Rules tương tác với các truy vấn.

Hành vi và giới hạn

Khi bạn làm việc với các truy vấn tổng hợp, hãy lưu ý những hành vi và hạn chế sau:

  • Bạn không thể dùng các truy vấn tổng hợp với trình nghe theo thời gian thực và truy vấn ngoại tuyến. Chỉ các truy vấn tổng hợp được hỗ trợ thông qua phản hồi trực tiếp của máy chủ. Các truy vấn chỉ được phân phát bởi phần phụ trợ Cloud Firestore, bỏ qua bộ nhớ đệm cục bộ và mọi bản cập nhật được lưu vào bộ nhớ đệm. Hành vi này giống hệt với các thao tác được thực hiện trong Cloud Firestoregiao dịch.

  • Nếu không thể phân giải một phép tổng hợp trong vòng 60 giây, thì phép tổng hợp đó sẽ trả về lỗi DEADLINE_EXCEEDED. Hiệu suất phụ thuộc vào cấu hình chỉ mục và kích thước của tập dữ liệu.

    Nếu không thể hoàn tất thao tác trong thời hạn 60 giây, thì một giải pháp thay thế có thể là sử dụng bộ đếm cho các tập dữ liệu lớn.

  • Các truy vấn tổng hợp đọc từ các mục chỉ mục và chỉ bao gồm các trường được lập chỉ mục.

  • Việc thêm một mệnh đề OrderBy vào một truy vấn tổng hợp sẽ giới hạn việc tổng hợp đối với những tài liệu có trường sắp xếp.

  • Đối với các phép tổng hợp sum()average(), các giá trị không phải là số sẽ bị bỏ qua. Các hàm tổng hợp sum()average() chỉ xem xét các giá trị số nguyên và giá trị số dấu phẩy động.

  • Khi kết hợp nhiều phép tổng hợp trong một truy vấn, hãy lưu ý rằng sum()average() bỏ qua các giá trị không phải là số trong khi count() bao gồm các giá trị không phải là số.

  • Nếu bạn kết hợp các phép tổng hợp trên nhiều trường, thì phép tính sẽ chỉ bao gồm những tài liệu có chứa tất cả các trường đó.

Giá

Giá cho các truy vấn tổng hợp phụ thuộc vào số lượng mục nhập chỉ mục mà truy vấn khớp. Bạn bị tính một số ít lượt đọc cho một số lượng lớn các mục khớp. Bạn sẽ bị tính một thao tác đọc cho mỗi lô có tối đa 1.000 mục nhập chỉ mục được đọc.

Để biết thêm thông tin về giá của truy vấn tổng hợp, hãy xem phần Truy vấn tổng hợp.