2
2

More than 3 years have passed since last update.

DynamoDB+Goでmapのデータを取得する

Posted at

はじめに

GoでDynamoDBのmapのデータを取りたいときのメモ。
単純な構成は結構ググったら出てくるが、複雑な構成はググっても出てこず、試行錯誤した。

TL;DR

  • DBの要素にmapが入っている場合 -> パターン1
  • mapがネストしている場合 -> パターン2
  • リストの中にmapがある場合 -> パターン3
  • mapを表現する構造体を定義する。
  • mapを表現した構造体は、struct tagにキー名をつける。
  • 各構造体のフィールドはエクスポートする。

DBの構成

こんな構成。mapがネストしていたり、リストの中にmapが入っていたり。

image.png

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)
}

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2