聚合查询会处理多个索引条目中的数据,然后返回单个摘要值。
Cloud Firestore 支持 count()
聚合查询。count()
可用于确定集合或查询中的文档数量。服务器会计算数量并且只是将结果(即一个整数)传回您的应用,而不会执行完整的查询,这样做既节省了文档读取费用,又减少了所需传输的字节数。
聚合查询依赖于您的查询已在使用的现有索引配置,并且会根据扫描到的索引条目数量按比例进行扩缩。这意味着,中小规模数据集的聚合过程通常会在 20-40 毫秒内完成,但延迟时间会随着计数项的数量增多而增加。
使用 count()
聚合
请参阅我们在获取数据部分中设置的示例数据。
以下 count()
聚合会返回 cities
集合中的城市总数。
Web 模块化 API
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
count()
聚合会考虑查询的所有过滤条件以及所有 limit
子句。
Web 模块化 API
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
Cloud Firestore 安全规则针对 count()
聚合查询的工作方式与针对返回文档的常规查询的工作方式相同。换句话说,当且仅当您的规则允许客户端执行某些集合或合集组查询时,客户端也可以对这些查询执行 count()
聚合操作。详细了解 Cloud Firestore 安全规则与查询之间的相互作用。
限制
请注意,count()
聚合查询存在以下限制:
count()
聚合查询目前只能通过直接服务器响应进行处理。查询只会通过 Cloud Firestore 后端进行处理,并且会跳过本地缓存和任何已缓冲的更新。此行为与 Cloud Firestore 事务内执行的操作相同。您目前无法将count()
查询与实时监听器和离线查询搭配使用。如果
count()
聚合无法在 60 秒内完成解析,则会返回DEADLINE_EXCEEDED
错误。聚合性能取决于您的索引配置以及数据集的规模。如果操作无法在 60 秒时限内完成,作为一种可能的解决方法,您可以针对大规模数据集使用计数器。
count()
聚合会从索引条目中读取数据,并且只对编入索引的字段进行计数。如果向查询添加
OrderBy
子句,则查询只会对存在排序字段的文档进行计数。
价格
count()
的价格取决于查询匹配的索引条目的数量。您需要为大量匹配的条目支付少量读取费用。
查看更详细的价格信息。