クリスマスは過ぎてしまいましたが参加してた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^)/