はじめに
GoでDynamoDBのmapのデータを取りたいときのメモ。
単純な構成は結構ググったら出てくるが、複雑な構成はググっても出てこず、試行錯誤した。
TL;DR
- DBの要素にmapが入っている場合 -> パターン1
- mapがネストしている場合 -> パターン2
- リストの中にmapがある場合 -> パターン3
- mapを表現する構造体を定義する。
- mapを表現した構造体は、struct tagにキー名をつける。
- 各構造体のフィールドはエクスポートする。
DBの構成
こんな構成。mapがネストしていたり、リストの中にmapが入っていたり。
aws cliでget-itemするとこんな感じ。
22:14:30 dynamo-sample aws dynamodb get-item --table-name user --key '{"id": {"S": "sample"} }' --endpoint-url http://localhost:8000 --output json
{
"Item": {
"basic": {
"M": {
"firstname": {
"S": "taro"
},
"address": {
"M": {
"city": {
"S": "Minatoku"
},
"pref": {
"S": "Tokyo"
}
}
},
"age": {
"N": "20"
},
"lastname": {
"S": "sample"
}
}
},
"logs": {
"L": [
{
"M": {
"time": {
"S": "2130"
}
}
},
{
"M": {
"time": {
"S": "2131"
}
}
}
]
},
"id": {
"S": "sample"
}
}
}
パターン1
シンプルなmapの場合。
basicは、
- firstname
- address
- age
- lastname
というmapをもっている。このうち、firstnameを取得するには、
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
"log"
)
type User struct {
Id string `dynamo:"id"`
Basic Basic `dynamo:"basic"`
}
type Basic struct {
First string `dynamo:"firstname"`
}
func main() {
db := dynamo.New(session.New(), &aws.Config{
Region: aws.String("ap-northeast-1"),
Endpoint: aws.String("http://localhost:8000"),
DisableSSL: aws.Bool(false),
})
table := db.Table("user")
var user User
if err := table.Get("id", "sample").One(&user); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", user)
}
となる。
ポイントは、
-
User
テーブルを表現する構造体を定義する。 -
Basic
は中に複数のmapをもっているので、Basicを表現する構造体は別に定義する。 - struct tagはテーブル名と同じものにする。
- 構造体のフィールドはエクスポートする。(フィールド名の先頭は大文字)こうしないとデータが取れない。ここがわかってなくてハマった。
type User struct {
Id string `dynamo:"id"`
Basic Basic `dynamo:"basic"`
}
次に、Basic
構造体を定義する。
ポイントとしては、struct tag
にはmapのキー名を定義する。ここがわからず、めちゃハマった。
type Basic struct {
First string `dynamo:"firstname"`
}
これで、実行すると、{Id:sample Basic:{First:taro}}
のように出力される。
また、user.Basic.First
のようにたどることができる。
パターン2
ネストされたmapの場合。
basicは、
- firstname
- address
- age
- lastname
というmapをもっている。このうち、addressは、さらにPrefやCityといったmapをもっている。
とはいえ、No1. シンプルなmap
と同じで、各mapを別構造体で定義し、struct tagにmapのキーを指定する。
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
"log"
)
type User struct {
Id string `dynamo:"id"`
Basic Basic `dynamo:"basic"`
}
type Basic struct {
First string `dynamo:"firstname"`
Address Address `dynamo:"address"`
}
type Address struct {
Pref string `dynamo:"pref"`
City string `dynamo:"city"`
}
func main() {
db := dynamo.New(session.New(), &aws.Config{
Region: aws.String("ap-northeast-1"),
Endpoint: aws.String("http://localhost:8000"),
DisableSSL: aws.Bool(false),
})
table := db.Table("user")
var user User
if err := table.Get("id", "sample").One(&user); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", user)
}
これで実行すると、{Id:sample Basic:{First:taro Address:{Pref:Tokyo City:Minatoku}}}
となる。
また、user.Basic.Address.Prefみたいにたどることができる。
パターン3
リスト内にmapがある場合。
logsはリスト内にmapをもっている。
ただし、これもここまでと同じで構造体を定義すれば取得できる。
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
"log"
)
type User struct {
Id string `dynamo:"id"`
Basic Basic `dynamo:"basic"`
Logs []Log `dynamo:"logs"`
}
type Basic struct {
First string `dynamo:"firstname"`
Address Address `dynamo:"address"`
}
type Address struct {
Pref string `dynamo:"pref"`
City string `dynamo:"city"`
}
type Log struct {
Time string `dynamo:"time"`
}
func main() {
db := dynamo.New(session.New(), &aws.Config{
Region: aws.String("ap-northeast-1"),
Endpoint: aws.String("http://localhost:8000"),
DisableSSL: aws.Bool(false),
})
table := db.Table("user")
var user User
if err := table.Get("id", "sample").One(&user); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", user)
}
最終的なコード
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
"log"
)
type User struct {
Id string `dynamo:"id"`
Basic Basic `dynamo:"basic"`
Logs []Log `dynamo:"logs"`
}
type Basic struct {
First string `dynamo:"firstname"`
Last string `dynamo:"lastname"`
Age int `dynamo:"age"`
Address Address `dynamo:"address"`
}
type Address struct {
Pref string `dynamo:"pref"`
City string `dynamo:"city"`
}
type Log struct {
Time string `dynamo:"time"`
}
func main() {
db := dynamo.New(session.New(), &aws.Config{
Region: aws.String("ap-northeast-1"),
Endpoint: aws.String("http://localhost:8000"),
DisableSSL: aws.Bool(false),
})
table := db.Table("user")
var user User
if err := table.Get("id", "sample").One(&user); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", user)
}