search
LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

Firestore(in Datastore mode)で、Projectionクエリを使って料金を節約する

クリスマスは過ぎてしまいましたが参加してたGCP Advent Calendarに穴が一つだけ空いてたので今更ながら埋めます^^;

最初に

Firestore (in Datastore Mode)でクエリを呼び出した場合、通常Query実行の1読み込みオペレーションに加えて、取得したエンティティの数だけ読み込みオペレーションがかかります。

大昔には読み込みオペレーションを節約する為にKey名にプロパティ内容を埋め込んでKeysOnlyクエリで取得するみたいな黒魔術が存在したこともありましたが、現在はProjectionクエリを利用して同様の節約を行うことが出来ます(しかも黒魔術と違ってプロパティ変更が可能です^^)。

Projectionクエリは、一般的なRDBでいうところのカラム指定SELECT(SELECT A, B, C FROM ...)を行うものです。
Firestore(in Datastore mode)内部の動きとしては、インデックス上のプロパティを使って結果を返す為、かかる料金はクエリ実行の1読み込みオペレーションのみで、エンティティ毎の読み込みオペレーションが無料になります。
つまり、例えば1000件読み込んだ場合料金は1/1001になります。

実装

本記事ではGoのClient Libraryを利用します。

datastore.QueryのProjectメソッドで取得したいプロパティ名を指定するだけです。

type Book struct {
    Title     string
    Category  string
    Price     int
    CreatedAt time.Time
}

func main() {
    ctx := context.Background()

    q := datastore.NewQuery("Book").Project("Title", "Price", "Category", "CreatedAt").Order("CreatedAt").Limit(1000)

    var books []*Book
    _, err := client.GetAll(ctx, q, &books)
    if err != nil {
        log.Fatal(err)
    }

    for _, b := range books {
        fmt.Printf("%+v\n", b)
    }

    fmt.Println("done")
}

複数のプロパティを指定する場合はカスタムインデックスが必要になります。

- kind: Book
  properties:
  - name: CreatedAt
  - name: Category
  - name: Price
  - name: Title

まとめ

Projectionクエリは結構マイナーな機能かな、と思っているのですが、うまく使うことで大幅にコストを減らすことが可能です。

旧Datastore時代からあった機能ですがグローバルクエリの場合インデックス遅延により最新のデータを取得しない可能性があるというデメリットもありました。
Firestoreになってクエリも強整合になったのでその弱点もなくなった認識です(ツヨイ!)

現状Datastore modeのみの機能ですが、Native modeにも欲しいところです。

参考資料

Projection queries
Pricing and Quota

それでは、よいお年を〜\(^o^)/

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
What you can do with signing up
1