LoginSignup
13
4

More than 1 year has passed since last update.

Firestoreでcountの集計がとれるようになっていたのでiOSで実装してみた

Last updated at Posted at 2022-10-12

こんにちは。virapture株式会社でCEOしながらラグナロク株式会社でもCKOとして働いている@mogmetです。
mogmet.jpg
一昔前の聖地巡礼したときの写真がgoogleにサジェストされました。あの花はとても名作なので是非みてない人は見てください。

本日はmonoさんが衝撃な機能をツイートしていたので実際に試してみた記事になります。(monoさん素敵な情報ツイートありがとうございますー!!)

というわけで、Firebaseのバージョン10.0.0から集計系の機能が入ってきたので早速紹介します。

Firestoreの count について

いままでFirestoreでcountを取得するためには全件取得するか、count用のフィールドを作って、ドキュメントが作られるたびにインクリメントするみたいな処理を作る必要がありました。
しかし、今回のこの機能を使えばさらっとcountがとれてしまうという素敵な機能になります!!

公式ドキュメントによるとQueryにcountが増えているようです。
https://firebase.google.com/docs/reference/swift/firebasefirestore/api/reference/Classes/Query#/c:objc(cs)FIRQuery(py)count

実装

今回のサンプルは下記リポジトリに置いておきました。

まず初期化します。

import SwiftUI
import Firebase
import FirebaseFirestore

@main
struct FirestoreCountApp: App {
    init() {
        FirebaseApp.configure()
        // emulatorを使わない場合は下記settingsをすべてコメントアウトする
        let settings = Firestore.firestore().settings
        settings.host = "localhost:8080"
        settings.isPersistenceEnabled = false
        settings.isSSLEnabled = false
        Firestore.firestore().settings = settings
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

実装はこんな感じ。

import SwiftUI
import FirebaseFirestore

struct ContentView: View {
    @State var countText: String = "none"
    var body: some View {
        VStack {
            Text(countText)
            Button {
                Task {
                    await loadCount()
                }
            } label: {
                Text("Load count")
            }
        }
        .padding()
    }
    func loadCount() async {
        let aggregateSnapshot = try! await Firestore.firestore().collection("users").count.getAggregation(source: .server)
        countText = aggregateSnapshot.count.stringValue
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

ここが肝になります。countがニョキッと生えてます。

let aggregateSnapshot = try! await Firestore.firestore()
    .collection("users").count.getAggregation(source: .server)

firestoreのデータの準備をしておきます。
image.png

ボタンを押して挙動を確認してみます。

before after
image.png image.png

リードコストは少なくなるのか?

多分 少なくなるというのが結論です。

実際に挙動を試してみたのですが、読み取りが一切カウントされませんでした。(webがまだcountに対応してない?)

image.png
(ちなみにぴょんとreadが飛び上がってるのはwebコンソールを開いてデータを確認したため上がってるだけです。)

emulatorもgetDocumentsしたときと結果がかわらなくて本当にリードコストが少なくなってるかは謎です。

image.png

一応ドキュメントでは下記の通り説明があります。

A query that counts the documents in the result set of this query.

The AggregateQuery query, when executed, counts the documents in the result set of this Query without actually downloading the documents.

Using the returned query to count the documents is efficient because only the final count, not the documents’ data, is downloaded. The returned query can even count the documents if the result set would be prohibitively large to download entirely (e.g. thousands of documents).

ざっくりいうと実際にダウンロードすることなく結果のカウントだけするから効率的だぜと言ってます。

なのでおそらく1read換算になるのでは・・・・?という判断です。

リアルタイム取得はできる?

結論でいうと 多分まだできない? になります。

理由としてはAggregateQueryにListenerを返すメソッドがないからになります。

ただ、AggregateQuery自体にはqueryを返すものが生えていてそこをたどればaddSnapshotListenerを呼び出すことはできるのですが、挙動的にいつも通りのコレクションの全リードが発生してそうな雰囲気でした。
(snapshotsのなかにデータが入っていた)

今後拡充される可能性はありますが、もう少し様子見な感じです。

(もし誰かやり方わかったら教えて下さい!)

まとめ

countがリードコストもかさまずにコールすることができるようになりました!
集計系は今後も増えそうな雰囲気なのでますますfirestoreが便利になっていくので期待です!

最後に、ワンナイト人狼オンラインというゲームを作ってます!よかったら遊んでね!

他にもCameconOffcha、問い合わせ対応が簡単にできるCSmart、フリーランスのコミュニティのNextFreelanceといったサービスも作ってるのでよかったら使ってね!

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

ラグナロクでもエンジニアやデザイナーのメンバーを募集しています!!楽しくぶち上げたい人はぜひお話ししましょう!!

13
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
4