【第3回】Go言語(Golang)入門~Firestoreデータ操作編~
IT技術
第3回~Go言語(Golang)入門~
(株)ライトコードの笹川(ささがわ)です。
今回でGo言語(Golang)入門3回目!
前回に引き続き、Firestoreについて書いていきます。
今回は、データの操作をしてみよう編です!
前回の記事はこちら
データを追加してみよう
前回同様、以下ドキュメントを参考に進めたいと思います。
【データを追加する】
https://firebase.google.com/docs/firestore/quickstart?hl=ja#add_data
今回も、初期化は忘れずに入れましょう!
1package main
2
3import (
4 "context"
5 "log"
6
7 firebase "firebase.google.com/go"
8 "google.golang.org/api/option"
9)
10
11func main() {
12 // 初期化
13 ctx := context.Background()
14 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
15 app, err := firebase.NewApp(ctx, nil, sa)
16 if err != nil {
17 log.Fatalln(err)
18 }
19
20 client, err := app.Firestore(ctx)
21 if err != nil {
22 log.Fatalln(err)
23 }
24
25 // データ追加
26 _, _, err = client.Collection("users").Add(ctx, map[string]interface{}{
27 "first": "Ada",
28 "last": "Lovelace",
29 "born": 1815,
30 })
31 if err != nil {
32 log.Fatalf("Failed adding alovelace: %v", err)
33 }
34
35 // 切断
36 defer client.Close()
37}
ドキュメントでは、各メソッドしかないのでちょっと迷いますよね!
これで実行をすると、下記のようにデータが追加されているのを確認することができます。
データ追加
さらに、別のデータも追加してみましょう。
1package main
2
3import (
4 "context"
5 "log"
6
7 firebase "firebase.google.com/go"
8 "google.golang.org/api/option"
9)
10
11func main() {
12 // 初期化
13 ctx := context.Background()
14 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
15 app, err := firebase.NewApp(ctx, nil, sa)
16 if err != nil {
17 log.Fatalln(err)
18 }
19
20 client, err := app.Firestore(ctx)
21 if err != nil {
22 log.Fatalln(err)
23 }
24
25 // データ追加
26 _, _, err = client.Collection("users").Add(ctx, map[string]interface{}{
27 "first": "Ada",
28 "middle": "Mathison",
29 "last": "Lovelace",
30 "born": 1815,
31 })
32 if err != nil {
33 log.Fatalf("Failed adding alovelace: %v", err)
34 }
35
36 // 切断
37 defer client.Close()
38}
実行
それでは、実行してみましょう!
データがしっかりと追加されていました!
データを読みとってみよう
下記に書いてある通りに記述してみましょう。
【データを読み取る】
https://firebase.google.com/docs/firestore/quickstart?hl=ja#read_data
初期化も忘れずにやりましょう!
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 firebase "firebase.google.com/go"
9 "google.golang.org/api/iterator"
10 "google.golang.org/api/option"
11)
12
13func main() {
14 // 初期化
15 ctx := context.Background()
16 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
17 app, err := firebase.NewApp(ctx, nil, sa)
18 if err != nil {
19 log.Fatalln(err)
20 }
21
22 client, err := app.Firestore(ctx)
23 if err != nil {
24 log.Fatalln(err)
25 }
26
27 // データ読み取り
28 iter := client.Collection("users").Documents(ctx)
29 for {
30 doc, err := iter.Next()
31 if err == iterator.Done {
32 break
33 }
34 if err != nil {
35 log.Fatalf("Failed to iterate: %v", err)
36 }
37 fmt.Println(doc.Data())
38 }
39
40 // 切断
41 defer client.Close()
42}
実行
実行してみましょう!
1$ go run main.go
2map[born:1815 first:Ada last:Lovelace middle:Mathison]
3map[born:1815 first:Ada last:Lovelace]
先程追加した2件のデータが読み取れています!
データを更新してみよう
こちらは、チュートリアルにないのですが、以下のドキュメントを参考にしてみました。
【Cloud Firestore にデータを追加する】
https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja
Addで追加する方法が見つからなかったので、Setで追加し、Setで更新してみます。
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "cloud.google.com/go/firestore"
9 firebase "firebase.google.com/go"
10 "google.golang.org/api/iterator"
11 "google.golang.org/api/option"
12)
13
14func main() {
15 // 初期化
16 ctx := context.Background()
17 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
18 app, err := firebase.NewApp(ctx, nil, sa)
19 if err != nil {
20 log.Fatalln(err)
21 }
22
23 client, err := app.Firestore(ctx)
24 if err != nil {
25 log.Fatalln(err)
26 }
27
28 // データ追加
29 _, err = client.Collection("users").Doc("user2").Set(ctx, map[string]interface{}{
30 "first": "Ada",
31 "middle": "Mathison",
32 "last": "Lovelace",
33 "born": 1815,
34 })
35 if err != nil {
36 log.Fatalf("Failed adding alovelace: %v", err)
37 }
38
39 // 切断
40 defer client.Close()
41}
実行するとデータ追加がされます。
firstを更新
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "cloud.google.com/go/firestore"
9 firebase "firebase.google.com/go"
10 "google.golang.org/api/iterator"
11 "google.golang.org/api/option"
12)
13
14func main() {
15 // 初期化
16 ctx := context.Background()
17 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
18 app, err := firebase.NewApp(ctx, nil, sa)
19 if err != nil {
20 log.Fatalln(err)
21 }
22
23 client, err := app.Firestore(ctx)
24 if err != nil {
25 log.Fatalln(err)
26 }
27
28 // データ更新
29 _, updateError := client.Collection("users").Doc("user2").Set(ctx, map[string]interface{}{
30 "first": "Yeah",
31 }, firestore.MergeAll)
32 if updateError != nil {
33 // Handle any errors in an appropriate way, such as returning them.
34 log.Printf("An error has occurred: %s", err)
35 }
36
37 // 切断
38 defer client.Close()
39}
実行
それでは、実行してみましょう!
ばっちり更新されました!
Addではなく「最初からSetをチュートリアルで書いてくれればいいのに」と思いました(笑)
データを削除してみよう
データ削除も、チュートリアルにはありません。
そのため、以下のドキュメントを参考にしたいと思います。
【Cloud Firestore からデータを削除する】
https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja
フィールドの削除
では、まずフィールドの削除をしてみます。
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "cloud.google.com/go/firestore"
9 firebase "firebase.google.com/go"
10 "google.golang.org/api/iterator"
11 "google.golang.org/api/option"
12)
13
14func main() {
15 // 初期化
16 ctx := context.Background()
17 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
18 app, err := firebase.NewApp(ctx, nil, sa)
19 if err != nil {
20 log.Fatalln(err)
21 }
22
23 client, err := app.Firestore(ctx)
24 if err != nil {
25 log.Fatalln(err)
26 }
27
28 // フィールド削除
29 _, errorDelete := client.Collection("users").Doc("user2").Update(ctx, []firestore.Update{
30 {
31 Path: "middle",
32 Value: firestore.Delete,
33 },
34 })
35 if errorDelete != nil {
36 // Handle any errors in an appropriate way, such as returning them.
37 log.Printf("An error has occurred: %s", err)
38 }
39
40 // 切断
41 defer client.Close()
42}
実行
実行してエラーがでなければ、成功です。
では、実際にデータを見てみましょう!
「middle」が消えていますね!
user2を削除してみる
このまま、この「user2」を削除してみます。
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "cloud.google.com/go/firestore"
9 firebase "firebase.google.com/go"
10 "google.golang.org/api/iterator"
11 "google.golang.org/api/option"
12)
13
14func main() {
15 // 初期化
16 ctx := context.Background()
17 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
18 app, err := firebase.NewApp(ctx, nil, sa)
19 if err != nil {
20 log.Fatalln(err)
21 }
22
23 client, err := app.Firestore(ctx)
24 if err != nil {
25 log.Fatalln(err)
26 }
27
28 // ドキュメント削除
29 _, errorDelete := client.Collection("users").Doc("uesr2").Delete(ctx)
30 if errorDelete != nil {
31 // Handle any errors in an appropriate way, such as returning them.
32 log.Printf("An error has occurred: %s", err)
33 }
34
35 // 切断
36 defer client.Close()
37}
エラーが出ないので成功です!
しかし、コンソール上だとデータが消えていません!
下記ドキュメントだとこのように書かれています。
【Cloud Firestore からデータを削除する】
https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja
警告: ドキュメントを削除しても、そのドキュメントのサブコレクションは削除されません。
ドキュメントを削除しても、Cloud Firestore はサブコレクション内のドキュメントを自動的には削除しません。サブコレクションのドキュメントには参照により引き続きアクセスできます。たとえば、パス /mycoll/mydoc/mysubcoll/mysubdoc にあるドキュメントには、/mycoll/mydoc の祖先ドキュメントを削除してもアクセスできます。
存在しない祖先ドキュメントはコンソールには表示されますが、クエリの結果やスナップショットには表示されません。
ドキュメントと、そのドキュメントのサブコレクション内のすべてのドキュメントを削除するには、手動での操作が必要です。詳しくは、コレクションを削除するをご覧ください。
手動で削除が必要ならば、なぜこの処理が用意されているんでしょうか...?
コレクションの削除
次は、コレクションの削除をしてみます。
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "cloud.google.com/go/firestore"
9 firebase "firebase.google.com/go"
10 "google.golang.org/api/iterator"
11 "google.golang.org/api/option"
12)
13
14func main() {
15 // 初期化
16 ctx := context.Background()
17 sa := option.WithCredentialsFile("path/to/serviceAccount.json")
18 app, err := firebase.NewApp(ctx, nil, sa)
19 if err != nil {
20 log.Fatalln(err)
21 }
22
23 client, err := app.Firestore(ctx)
24 if err != nil {
25 log.Fatalln(err)
26 }
27 ref := client.Collection("users")
28 deleteCollection(ctx, client, ref, 10)
29
30}
31
32func deleteCollection(ctx context.Context, client *firestore.Client,
33 ref *firestore.CollectionRef, batchSize int) error {
34
35 for {
36 // Get a batch of documents
37 iter := ref.Limit(batchSize).Documents(ctx)
38 numDeleted := 0
39
40 // Iterate through the documents, adding
41 // a delete operation for each one to a
42 // WriteBatch.
43 batch := client.Batch()
44 for {
45 doc, err := iter.Next()
46 if err == iterator.Done {
47 break
48 }
49 if err != nil {
50 return err
51 }
52
53 batch.Delete(doc.Ref)
54 numDeleted++
55 }
56
57 // If there are no documents to delete,
58 // the process is over.
59 if numDeleted == 0 {
60 return nil
61 }
62
63 _, err := batch.Commit(ctx)
64 if err != nil {
65 return err
66 }
67 }
68}
こちらは、エラーハンドリングを端折ってしまったので、ビルド時にエラーが出なければ、そのまま実行で問題ありません。
「uesrs」というidは、消えないようです。
確かに処理の内容としては、usersのドキュメントとコレクションを「for」で消していくという処理ですのでこうなりますね。
データ削除については、なんだか弱い気がしました。
第4回へつづく!
データの操作について、いろいろ試してみました。
今回は、Go言語(Golang)より、Firestoreの使い方のほうにつまずいた印象がありました。
データの扱いは「追加」「読み取り」「更新」「削除」をやれないと意味ないですからね!
今回、作成したgoファイルはこちらのリポジトリにて管理しています。
次回の記事はこちら
オススメのGo入門本
こちらの記事もオススメ!
2020.08.08Go言語 特集知識編人気急上昇中のGo言語(Golang)って何だ?実装編Go言語(Golang)入門...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
第1回の記事はこちら
2019.09.13【第1回】Go言語(Golang)入門~環境構築編~第1回~Go言語(Golang)を習得したい!~笹川先生(株)ライトコードでモバイルアプリケーション開発をしている笹川...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
新潟生まれ新潟育ち本業はモバイルアプリエンジニア。 日々、猫(犬)エンジニアとして活躍中!
おすすめ記事
immichを知ってほしい
2024.10.31