GAE+GOでGCP上のFirestoreを使ってみる

datastoreを使ってイソイソ開発をしていたらFirestoreなるものがいつの間にか出ていた。今後はこっちが主流になるとのこと。まじか。

ということで GAE+GOでFirestoreを使ってみるよ。

ちなみに、この記事のやり方はGCP上のFirestoreを使う方法なのでFirebaseのFirestoreを使う方法は別の記事を探してくださいませ。

DatastoreとFirestoreは一回どちらかを選んでしまうと、片方は同じプロジェクト上では使えなくなるので、すでにDatastoreをプロジェクトを作っている場合は新しくFirestore用にプロジェクトを作り直す必要がある。

まずはGCPでプロジェクトを作成し、Firestoreの設定画面へ行く。

![スクリーンショット 2019-03-26 14.13.16.png](https://qiita-image-store.s3.amazonaws.com/0/35536/4d39e028-0d0f-2558-6ad4-6f47f7e9d836.png)

Datastoreっぽく使いたい場合はDatastoreモードというのがあるらしい。
今回は普通に使いたいのでネイティブモードを選択。

![スクリーンショット 2019-03-26 14.15.48.png](https://qiita-image-store.s3.amazonaws.com/0/35536/b7e8f30d-e541-7106-3e2a-88876d3ee3f5.png)

次にデータベースの場所を選択する。一回選ぶとやり直せないという怖い文言があるので本番用に使う場合は将来も考えて選択するのが良さそう。今回はTokyoにしておいた。

![スクリーンショット 2019-03-26 14.17.52.png](https://qiita-image-store.s3.amazonaws.com/0/35536/5d232dda-ecc7-2b67-5e6a-be8f6cb851bd.png)

作成には数分かかる。

![スクリーンショット 2019-03-26 14.18.29.png](https://qiita-image-store.s3.amazonaws.com/0/35536/d35f4291-ddbf-9841-ec3e-73e7f5b5380b.png)

完了すると上記のような管理画面が表示される。

次にローカル環境からFirestoreに繋げるために「サービス アカウント キー」の設定をする。

APIとサービス画面の認証情報から「認証情報を作成」を選択。
![スクリーンショット 2019-03-20 21.15.06.png](https://qiita-image-store.s3.amazonaws.com/0/35536/322a3b84-783d-3529-0494-d902b00e93f8.png)

サービスアカウントキーを選択して
![スクリーンショット 2019-03-20 21.15.16.png](https://qiita-image-store.s3.amazonaws.com/0/35536/78f1f290-bb08-a02e-f86f-fc9c808f1f77.png)

キーのタイプはJSONにしておく。
![スクリーンショット 2019-03-20 21.15.33.png](https://qiita-image-store.s3.amazonaws.com/0/35536/bf12a4be-ae5a-52e0-367d-03fda51d7cc1.png)

最後に作成を実行すると、PCにjsonファイルがダウンロードされる。そのjsonファイルを以下の環境変数に設定すればGCP側の準備は完了。

```
export GOOGLE_APPLICATION_CREDENTIALS="/[PATH]/[FILE_NAME].json"
```

GAEでの開発に慣れていると色々設定をするのに違和感を覚えるかもしれないが、Detastoreと違ってFirestoreはローカル環境に実行環境が作られない。そのため開発時にもリモートのFirestoreに繋げに行くために必要らしい。

ここまでくればあとは結構簡単。
公式のドキュメント通りにやれば拍子抜けするほどあっさりと接続できる。


```sh
# gcpのライブラリを入れてなければ入れる
go get "cloud.google.com/go"
```

クライアント生成

```go
// firestoreをインポートする
import "cloud.google.com/go/firestore"

//GCPのプロジェクトID
projectID := "YOUR_PROJECT_ID"

//ctxはappengineのコンテキスト
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
        log.Fatalf("クライアント作成失敗: %v", err)
}

defer client.Close()
```

データ追加

```golang

//インターフェースバージョン
_, _, err = client.Collection("users").Add(ctx, map[string]interface{}{
        "Name": "Hoge Neko",
        "Age":  "10",
})
if err != nil {
        log.Fatalf("追加失敗: %v", err)
}

//構造体でも可能
type Users struct {
  Id   string
  Name string
  Age  int64
  CreatedAt time.Time
}

_, _, err = client.Collection("users").Add(ctx, Users{
        Name: "ほげ",
        Age:  22,
        CreatedAt: time.Now(),
})
if err != nil {
        log.Fatalf("追加失敗: %v", err)
}

```

コード実行後にGCPの管理画面で確認。ちゃんと登録できた。

![スクリーンショット 2019-03-26 13.48.49.png](https://qiita-image-store.s3.amazonaws.com/0/35536/25a24f28-628e-d484-b9ce-550c32cc9207.png)

Idの部分はデータを取得した時にドキュメントIdを格納するために用意してある。登録時には使ってない。この辺はもっとベストプラクティスがある気もしてる。

データ取得時のコードはこんな感じ

```golang

	iter := client.Collection("users").OrderBy("CreatedAt", firestore.Asc).Limit("12").Documents(ctx)

    var users []Users

	for {
		doc, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatalf("エラー: %v", err)
		}

		milestone = append(users, Milestone{
			Id:        doc.Ref.ID,
			Name:      getData["Name"].(string),
			Age:       getData["Age"].(int64),
			CreatedAt: getData["MilestoneDate"].(time.Time),
		})
```

情報があまりなくて少し迷ったがidは「doc.Ref.ID」で取得できる模様。

以上、あとは以下の公式から調べた方が早いと思うのでそちらを参考にしてみてください。

https://cloud.google.com/firestore/docs/quickstart-servers