Firestoreの集約クエリ (aggregation queries) を使用すると、複数のドキュメントの統計的な操作が簡単に行えます。
具体的には以下の3種類のクエリがあります。
- count
- sum
- average
公式ドキュメントではSwiftでのFirestoreのcountクエリの使い方についての説明がありましたが、sumやaverageに関する具体的なSwiftでの実装例は見つかりませんでした。そこで、この記事ではこれら3つのクエリ(count、sum、average)をSwiftでどのように使うかについて解説していきたいと思います。
また、料金的なメリットもありますので、それについても解説していきます。
実装方法
説明するにあたって、このような構造のコレクションがあるとします。
- users # (Collection)
- user1 # (Document ID)
- name: "Mike"
- age: 10
- user2
- name: "Takeshi"
- age: 21
- user3
- name: "Taro"
- age: 20
count
countクエリではコレクションまたはクエリ内のドキュメントの数を取得することができます。
以下の例は20歳以上のユーザー数を取得するコードです。
let count = try await Firestore.firestore()
.collection("users")
.whereField("age", isGreaterThanOrEqualTo: 20)
.count
.getAggregation(source: .server)
.count
.intValue
print(count) // 2
sum
sumクエリでは、コレクションまたはクエリ内の特定のfieldの合計値を取得することができます。
以下の例は全てのユーザーの歳を足して、その結果を取得するコードになっています。
let sum = try await Firestore.firestore()
.collection("posts")
.aggregate([.sum("age")])
.getAggregation(source: .server)
.get(.sum("age")) as? Int
print(sum) // Optional(51)
average
averageクエリでは、コレクションまたはクエリ内の特定のfieldの平均値を取得することができます。
以下の例はユーザーの平均年齢を取得するコードになっています。
let averageAge = try await Firestore.firestore()
.collection("posts")
.aggregate([.average("age")])
.getAggregation(source: .server)
.get(.average("age")) as? Double
print(averageAge) // Optional(17)
また、複数のfieldに対して集約クエリを実行することも可能です。
let aggregateQuerySnapshot = try await Firestore.firestore()
.collection("posts")
.aggregate([.average("age"), .sum("age")])
.getAggregation(source: .server)
let sumAge = aggregateQuerySnapshot.get(.sum("age")) as? Int
let averageAge = aggregateQuerySnapshot.get(.average("age")) as? Double
print(sumAge) // Optional(51)
print(averageAge) // Optional(17)
料金的なメリット
通常、Firestoreは読み取り・書き込み・削除を行うドキュメントの数に対して課金されます。
なので、1000個のドキュメントを読み取ったら1000回分の課金がなされます。
一方、集約クエリの場合は1000個のドキュメントにつき1回のドキュメント読み取り料金が発生します。
これにより、大幅な費用の削減を行うことができます。
しかし、集約する対象のドキュメントが1件であっても1回のドキュメント読み取り量が発生しますので注意してください。
参考