Overview
firestore でドキュメントを操作するベースとなる方法を記載します。 ※ Go の実装で書いてます。
ref: https://godoc.org/cloud.google.com/go/firestore
Firestore の基本的な操作
取得
Get
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } ref, err := client.Collection("$CollectionName").Doc("$DocumentID").Get(ctx) if err != nil { // TODO: Handle error }
ref: https://godoc.org/cloud.google.com/go/firestore#DocumentRef.Get
GetAll
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } dss, err := client.Collectipn("$CollectionName").Documents(ctx).GetAll() if err != nil { // TODO: Handle error } dsts := make([]*DistStruct, len(refs)) for i, ss := range dss { var dst = DistSturct{} if err := ss.DataTo(&dst); err != nil { // Handle Error } dsts[i] = &dst }
ref:
- https://godoc.org/cloud.google.com/go/firestore#CollectionIterator.GetAll
- https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja#get_multiple_documents_from_a_collection
追記
公式のドキュメントに記載されている実装方法は https://godoc.org/cloud.google.com/go/firestore#DocumentIterator を取得してからループで一つ一つマッピングしていく実装方針が記載されていますが、https://godoc.org/cloud.google.com/go/firestore#DocumentSnapshot を先に取り出したほうがその後 Slice にマッピングする時に Slice を length 指定でメモリ効率化できるので実装方針としてはそちらを採用する方がいいのでは?と思いました。
Save
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } src := map[string]interface{}{} ref, result, err := client.Collection("$CollectionName").Add(ctx)
ref: https://godoc.org/cloud.google.com/go/firestore#CollectionRef.Add
更新
ctx := context.Background() client, err := firestore.NewClient(ctx, "$projectID") if err != nil { // TODO: Handle error. } updates := []firestore.Update { {Path: "$updateTargetField", Value: interface{}{} } } if err := client.Collection("$DocumentName").Update(ctx, updates); err != nil { // TODO: Handle error. }
ref: https://godoc.org/cloud.google.com/go/firestore#DocumentRef.Update
firestore.FieldPath
Update
構造体の中に FieldPath
がありますが、ある Document 内部の Filed が入れ子の場合に特定の field を更新したい場合に使います。
ref: https://firebase.google.com/docs/reference/node/firebase.firestore.FieldPath
// A FieldPath is a non-empty sequence of non-empty fields that reference a value. // // A FieldPath value should only be necessary if one of the field names contains // one of the runes ".˜*/[]". Most methods accept a simpler form of field path // as a string in which the individual fields are separated by dots. // For example, // []string{"a", "b"} // is equivalent to the string form // "a.b" // but // []string{"*"} // has no equivalent string form. type FieldPath []string
ref: https://github.com/googleapis/google-cloud-go/blob/master/firestore/fieldpath.go#L31-L43
そのため以下のような構造のドキュメントを考えた時に
type Article struct { User User `json:"user" firestore:"user"` } type User struct { Name string `json:"name" firestore:"name"` Age int64 `json:"age" firestore:"age"` }
Article 内部のユーザーの名前を変更したい時に以下のような FieldPath を組み立てることになります。
fp := []string{"user", "name"} update := []firestore.Update {FieldPath: fp, Value: "Taro"} if err := client.Collection("Article").Update(ctx, update); err != nil { // TODO: Handle error. }
Transaction
if err := client.RunInTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction){ // Transaction }); err != nil { // TODO: Handle error. }
ref: https://godoc.org/cloud.google.com/go/firestore#Transaction