Help us understand the problem. What is going on with this article?

AppEngine Go でCloud Firestoreを使う

More than 1 year has passed since last update.

AppEngine GoでCloud Firestoreを使う

こんにちは、今回はFireBaseのCloud FirestoreをAppEngine Goから使う方法を紹介しようと思います。
AppEngineからの使い方を紹介している記事は調べた感じなさそうだったので自分のメモを兼ねてまとめていきます。

はじめに

ご注意:
プロジェクトの課金を有効化しないとデプロイ後の動作でCloud FirestoreとのSocket通信時にエラーとなります。課金を有効化してからお試し下さい。
(2018/10/17 追記)

AppEngineでFireStoreを使う場合、AppEngineインスタンスの作成よりも先にFireBaseプロジェクトを作成してFireStoreを有効化、GCPプロジェクトとの紐付けを行って下さい。
Cloud DatastoreとFireStoreは同一プロジェクトに共存できないため先にFireStoreを有効化しないとDatastoreしか使えません。(2018/06/21現在)

FireBaseプロジェクトの作成は下記コンソール(WEB)から
FireBaseConsole

今回はFireStoreをAppEngine Goから使うことを目的としていますので、まだAppEngine Goの環境を整えていない方は以前書いたGAE Go 開発環境の構築からテストアプリのデプロイまで【MacOS】を御覧ください。※Mac OS以外の方は各自検索

環境構築が終わりましたらGoのプロジェクトフォルダの構成までお願いします。
参考までに構成について書いた記事はこちらです。

ソースコード

開発する環境の構築とフォルダの構成が完了したところで、早速コードを書いていこうと思います。
基本的にはFireBase公式のドキュメントを参考に行いますが、AppEngineについてのドキュメントではないのでご注意下さい。

Cloud Firestore を初期化する

公式ドキュメントのGoogle Cloud Platform で初期化するを参考に行いますが、早速ここでAppEngineと通常のGoでは違いが出てきます。

app.go
import (
    firebase "firebase.google.com/go"
    "google.golang.org/api/iterator"
    "google.golang.org/appengine"
    "google.golang.org/appengine/log"
)
app.go
ctx := appengine.NewContext(r) // rはHandlerの引数 *http.Request

projectID := "YOUR-GCP-PROJECT-ID" //本番では直書きしないほうがいい
conf := &firebase.Config{ProjectID: projectID}
app, err := firebase.NewApp(ctx, conf) // ここでAppEngineのコンテキストが使えます

if err != nil {
    panic(err)
}

client, err := app.Firestore(ctx)

if err != nil {
    panic(err)
}

defer client.Close()

ここで注目すべきはAppEngineのコンテキストをそのまま使える点です。
公式ドキュメントには書いていないため実際にコードを書いてみるまでわかりませんでした。
恐らくここでハマる人が多いのではないでしょうか?
ここさえクリアできれば後は公式ドキュメント通りですので非常に楽です。

この記事での目的はAppEngine GoからFireStoreを使うことですので以下はあまり詳しく書きません。
公式ドキュメントを読んで進めて下さい。

データの追加

このあたりは公式のドキュメントそのままです

app.go
_, _, err = client.Collection("users").Add(ctx, map[string]interface{}{
    "first": "Ada", // key:valueで追加できます
    "last":  "Lovelace",
    "born":  1815,
})

if err != nil {
    log.Debugf(ctx, "Failed adding alovelace: %v", err)
}

データを読み取る

こちらも公式ドキュメントそのまま

app.go
iter := client.Collection("users").Documents(ctx)
for {
    doc, err := iter.Next()

    if err == iterator.Done {
        break
    }

    if err != nil {
        log.Debugf(ctx, "Failed to iterate: %v", err)
    }

    fmt.Println(doc.Data()) // この部分はAppEngineLogなりFprintなりに変更
}

クエリ

クエリは.Where("key", "オペレータ", 値)で行えます。
.Where("name", "==", name).Where("age", "==", age)などつなげることも可能です。

app.go
name := "Jack"

iter := client.Collection("users").Where("name", "==", name).Documents(ctx)
for {
    doc, err := iter.Next()

    if err == iterator.Done {
        break
    }

    if err != nil {
        log.Debugf(ctx, "Failed to iterate: %v", err)
    }

    fmt.Println(doc.Data()) // この部分はAppEngineLogなりFprintなりに変更
}

ドキュメントを削除する

データ削除に関する公式ドキュメント

app.go
_, err := client.Collection("cities").Doc("DC").Delete(ctx)

if err != nil {
    return err
}

フィールドを削除する

app.go
_, err := client.Collection("cities").Doc("BJ").Update(ctx, []firestore.Update{
    {
        Path:  "capital",
        Value: firestore.Delete,
    },
})

if err != nil {
    return err
}

コレクションを削除する

app.go
ref *firestore.CollectionRef, batchSize int) error {

    for {
        // Get a batch of documents
        iter := ref.Limit(batchSize).Documents(ctx)
        numDeleted := 0

        // Iterate through the documents, adding
        // a delete operation for each one to a
        // WriteBatch.
        batch := client.Batch()

        for {
            doc, err := iter.Next()

            if err == iterator.Done {
                break
            }

            if err != nil {
                return err
            }

            batch.Delete(doc.Ref)
            numDeleted++
        }

        // If there are no documents to delete,
        // the process is over.

        if numDeleted == 0 {
            return nil
        }

        _, err := batch.Commit(ctx)

        if err != nil {
            return err
        }
    }

あとがき

今回も前回に引き続きAppEngine Goの内容となりました。
まだまだ日本語ドキュメントが豊富ではないAppEngine Goをこれから始める人の参考になればと思います。
間違っている点などありましたらコメント等でお知らせ下さい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away