🦑
(golang)firestore databaseのページネーションによるコレクション全件取得
背景
- 今まではコレクション内の全データを一括取得していたが、下記のエラーが発生した。
rpc error: code = Unavailable desc = Query
timed out. Please try either limiting the entities scanned, or run with an updated index configuration.
- ドキュメントのデータが増え過ぎたことにより、一括取得できなくなったっぽい。
- なので、一括取得ではなく、ページネーションによる分割取得をデータを取得する必要があった
やりたいこと
- firestore databaseのドキュメント取得時にページネーションを使って取得したい
- 取得したコレクションは指定する型のスライスに詰めたい
結論
type Users struct {
ID string `json:"id"`
CreatedAt string `json:"createdAt"`
}
func FetchUsers() ([]*Users, error) {
collection := firestoreClient.Collection("users")
var slice []*Uses
var lastDocument *fs.DocumentSnapshot
size := 100
for {
query := collection.OrderBy("createdAt", fs.Asc).Limit(size)
if lastDocument != nil {
query = query.StartAfter(lastDocument.Data()["createdAt"])
}
documents, err := query.Documents(ctx).GetAll()
if err != nil {
return nil, errors.Wrap(err)
}
for _, doc := range documents {
b, err := json.Marshal(doc.Data())
if err != nil {
return nil, errors.Wrap(err)
}
resp := &Users{}
if err := json.Unmarshal(b, resp); err != nil {
return nil, errors.Wrap(err)
}
slice = append(slice, resp)
}
if len(documents) != size {
break
}
lastDocument = documents[(len(documents) - 1)]
}
return slice, nil
}
その他
- 上記のコードはこのリンクの良コードを参考に
構造体でパース+スライスに詰め詰めの処理
を追加しただけです。- この記事で素晴らしいなと思った点は
- 公式にもページネーションを用いた実装はあるが、初回処理とそれ以降の処理をfor文で綺麗にまとめてる
- ページネーションの終了のトリガーを
limit
と実際に取得した件数
を比較しているアイディアが素敵
- この記事で素晴らしいなと思った点は
Discussion