BigQuery はクエリが非常に高速なため、API クライアントを用いたアプリケーションからデータをクエリするケースも多いかと思います。
また、最近は Go を使ったアプリケーション開発の機会も増えてきました。
そこでこの記事では、BigQuery からデータを取得する際に RECORD 型を Go のネストした構造体(struct) にマッピングする方法を説明します。
例として挙げる BigQuery のテーブル request_logs
は、以下の表のようになっているとします。
カラム名 | データ型 | REQUIRED or NULLABLE |
---|---|---|
timestamp | TIMESTAMP | REQUIRED |
request_info | RECORD | NULLABLE |
request_info.path | STRING | NULLABLE |
request_info.method | STRING | NULLABLE |
request_info
が RECORD 型になっており、STRING 型の path
と method
を持っています。
このテーブルに対して下記のような SELECT クエリを発行したいとします。
SELECT
`timestamp`,
`request_info`
FROM
`request_logs`
WHERE
DATE(`timestamp`) = "2022-06-20"
ORDER BY `timestamp`
LIMIT 100;
Go の BigQuery クライアントから上記のクエリを発行し、 request_info
をネストした構造体にマッピングして取得することを考えます。
BigQuery の RECORD 型を Go の構造体にマッピングして取得するには、 bigquery
構造体タグ(Struct Tags) を使って構造体を定義します。
例えば下記のようになるでしょう。
type RequestLog struct {
Timestamp time.Time `bigquery:"timestamp"`
RequestInfo *RequestInfo `bigquery:"request_info,nullable"`
}
type RequestInfo struct {
Path string `bigquery:"path,nullable"`
Method string `bigquery:"method,nullable"`
}
bigquery
構造体タグを使って、フィールドごとに対応するカラム名を記述します。上記の例では Timestamp
フィールドに対応するカラム名は timestamp
です。
また、NULL許容の場合は nullable
も記述します。
RECORD 型に対応するフィールドは、構造体か構造体のポインタにします。REPEATED の場合はスライスとして定義します。
A repeated field corresponds to a slice or array of the element type. A STRUCT type (RECORD or nested schema) corresponds to a nested struct or struct pointer.
以上を踏まえて、最後に実際のコード例を示します。
import (
"context"
"fmt"
"io"
"cloud.google.com/go/bigquery"
"google.golang.org/api/iterator"
)
type RequestLog struct {
Timestamp time.Time `bigquery:"timestamp"`
RequestInfo *RequestInfo `bigquery:"request_info,nullable"`
}
type RequestInfo struct {
Path string `bigquery:"path,nullable"`
Method string `bigquery:"method,nullable"`
}
func queryExample(ctx context.Contest, projectID string) error {
// projectID := "my-project-id"
client, err := bigquery.NewClient(ctx, projectID)
if err != nil {
return fmt.Errorf("bigquery.NewClient: %v", err)
}
defer client.Close()
q := client.Query(
"SELECT " +
"`timestamp`, " +
"`request_info` " +
"FROM `<PROJECT_ID>.<DATASET>.request_logs` " +
"WHERE " +
"DATE(`timestamp`) = '2022-06-20' "
"ORDER BY `timestamp` " +
"LIMIT 100")
job, err := q.Run(ctx)
if err != nil {
return err
}
status, err := job.Wait(ctx)
if err != nil {
return err
}
if err := status.Err(); err != nil {
return err
}
var requestLogs []*RequestLog
it, err := job.Read(ctx)
for {
var requestLog RequestLog
err := it.Next(&requestLog)
if err == iterator.Done {
break
}
if err != nil {
return err
}
requestLogs = append(requestLogs, &requestLog)
}
fmt.Printf("%#v", requestLogs)
return nil
}
requestLog.RequestInfo.Path
のようにしてネストされたデータにアクセスすることができます。
また、timestamp
が日本時間(JST) で欲しい場合は次のようにします。
loc, err := time.LoadLocation("Asia/Tokyo")
if err != nil {
return err
}
for {
//
// 省略
//
requestLog.Timestamp = requestLog.Timestamp.In(loc) // 追加
requestLogs = append(requestLogs, &requestLog)
}
以上です。
この記事では、BigQuery からデータを取得する際に RECORD 型を Go のネストした構造体(struct) にマッピングする方法を説明しました。
コメントを送る
コメントはブログオーナーのみ閲覧できます