今回はGoでBigQueryからデータを読み出す方法について紹介する。
サンプルとして、このようなデータが入ったBigQueryのテーブルがあるとする。
テーブル名: test
フィールド名 | タイプ | モード |
---|---|---|
string_column | STRING | NULLABLE |
integer_column | INTEGER | NULLABLE |
date_column | DATE | NULLABLE |
timestamp_column | TIMESTAMP | NULLABLE |
データ
string_column | integer_column | date_column | timestamp_column |
---|---|---|---|
hoge1 | 1 | 2019-09-01 | 2019-09-01 00:00:00 UTC |
hoge2 | 2 | 2019-09-02 | 2019-09-02 00:00:00 UTC |
hoge3 | 3 | 2019-09-03 | 2019-09-03 00:00:00 UTC |
Goからデータを読み出すのにcloud.google.com/go/bigquery
パッケージを使う。
BigQueryに対してクエリを投げるには、まず下記のようにclientを準備しておく。
ctx := context.Background()
client, err := pkgbigquery.NewClient(ctx, projectID)
if err != nil {
// error handling
}
そしてクエリを記述する。
q := "SELECT " +
"string_column as StringColumn, " +
"integer_column as IntegerColumn, " +
"date_column as DateColumn, " +
"timestamp_column as TimestampColumn " +
"FROM `" + projectID + "." + dataset + ".test` "
実際にクエリを投げるRead
メソッドを実行する。Docの通りである。
it, err := client.Query(q).Read(ctx)
if err != nil {
return nil, err
}
得られたイテレータからデータを取得する。これもDocの通り。
var hoges []*hoge
for {
var h hoge
err := it.Next(&h)
if err == iterator.Done {
break
}
if err != nil {
return nil, err
}
hoges = append(hoges, &h)
}
BigQueryデータを構造体へマッピングするのはit.Next(&h)
の部分が行っている。
ちなみにhoge
は下記のような構造体である。
type hoge struct {
StringColumn string
IntegerColumn int64
DateColumn civil.Date
TimestampColumn time.Time
}
ただし、注意点として、構造体のフィールド名とBigQueryのデータのカラム名が同じでないといけない。
今回のサンプルのテーブルではカラム名がstring_column
などのようにスネークケースであるため、クエリ中で string_column as StringColumn
として記述することでBigQuery側のカラム名をGoの構造体のフィールド名に合わせている。
また、BigQueryのデータ型とGoの構造体のフィールドのデータ型との対応についてはライブラリ中のコメントに記述がある。下記はその引用である。
STRING string
BOOL bool
INTEGER int, int8, int16, int32, int64, uint8, uint16, uint32
FLOAT float32, float64
BYTES []byte
TIMESTAMP time.Time
DATE civil.Date
TIME civil.Time
DATETIME civil.DateTime
以上、説明してきたものをすべてまとめて、テーブルのレコードをすべて取得して中身をPrintlnで出力するコードは、下記になる。
package main
import (
"context"
"fmt"
"log"
"os"
"time"
pkgbigquery "cloud.google.com/go/bigquery"
"cloud.google.com/go/civil"
"google.golang.org/api/iterator"
)
var projectID string
var dataset string
func init() {
projectID = os.Getenv("GCP_PROJECT")
dataset = os.Getenv("BQ_DATASET")
}
func main() {
ctx := context.Background()
client, err := pkgbigquery.NewClient(ctx, projectID)
if err != nil {
log.Fatal(err)
}
hoges, err := queryfunc(ctx, client)
if err != nil {
log.Fatal(err)
}
for _, v := range hoges {
fmt.Println(*v)
}
}
type hoge struct {
StringColumn string
IntegerColumn int64
DateColumn civil.Date
TimestampColumn time.Time
}
func queryfunc(ctx context.Context, client *pkgbigquery.Client) ([]*hoge, error) {
q := "SELECT " +
"string_column as StringColumn, " +
"integer_column as IntegerColumn, " +
"date_column as DateColumn, " +
"timestamp_column as TimestampColumn " +
"FROM `" + projectID + "." + dataset + ".test` "
it, err := client.Query(q).Read(ctx)
if err != nil {
return nil, err
}
var hoges []*hoge
for {
var h hoge
err := it.Next(&h)
if err == iterator.Done {
break
}
if err != nil {
return nil, err
}
hoges = append(hoges, &h)
}
return hoges, nil
}
まとめ
- GoからBigQueryのデータを読み出すのは簡単
cloud.google.com/go/bigquery
パッケージを使う- 構造体へのマッピングもDocの例に従えばできる
- 構造体のデータ型とBigQueryのデータ型の対応はソースコード中に記載がある
- 構造体のフィールド名がBigQuery側と合っていないとマッピングされないので注意