LoginSignup
47
32

More than 5 years have passed since last update.

DynamoDBからデータを取得

Last updated at Posted at 2017-12-15

こんな感じの、毎日名前が変えられる謎のUserNameテーブルがあるとします。
DynamoDB · AWS Console.png

パーティションキーとソートキー

IDとDate(データ登録日)によってユニークが決まるようなテーブルの場合、
IDをパーティションキー、Dateをソートキーと設定するといいようです。
http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GuidelinesForTables.html

GetItem

GetItemを使用すると、ユニークキーを指定してデータが1つ取得できます。
http://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#DynamoDB.GetItem

以下の例では、dynamodbから取得後、User構造体に入れたりJsonにしたりして遊んでます。

dynamodb-get-item.go
package main

import (
    "encoding/json"
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

type User struct {
    UserID int    `json:"user_id" dynamodbav:"UserID"`
    Date   string `json:"date" dynamodbav:"Date"`
    Time   string `json:"time" dynamodbav:"Time"`
    Name   string `json:"name" dynamodbav:"Name"`
}

func main() {
    svc := dynamodb.New(session.New(), aws.NewConfig().WithRegion("ap-northeast-1"))

    input := &dynamodb.GetItemInput{
        TableName: aws.String("UserName"),
        Key: map[string]*dynamodb.AttributeValue{
            "UserID": {
                N: aws.String("1"),
            },
            "Date": {
                S: aws.String("20171215"),
            },
        },
    }

    result, err := svc.GetItem(input)
    if err != nil {
        fmt.Println("[GetItem Error]", err)
        return
    }

    user := &User{}
    if err := dynamodbattribute.UnmarshalMap(result.Item, user); err != nil {
        fmt.Println("[Unmarshal Error]", err)
        return
    }

    fmt.Println(result)

    j, _ := json.Marshal(user)
    fmt.Println(string(j))
}
$ go run dynamodb-get-item.go
{
  Item: {
    UserID: {
      N: "1"
    },
    Date: {
      S: "20171215"
    },
    Time: {
      S: "20171215120000"
    },
    Name: {
      S: "hoge"
    }
  }
}
{"user_id":1,"date":"20171215","time":"20171215120000","name":"hoge"}

Query

ユーザの名前変更履歴が見たい!とかあると思います。
そんな時はQueryで検索します。(GetItemsとかは無いようです)
http://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#DynamoDB.Query

dynamodb-query.go
package main

import (
    "encoding/json"
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

type User struct {
    UserID int    `json:"user_id" dynamodbav:"UserID"`
    Date   string `json:"date" dynamodbav:"Date"`
    Time   string `json:"time" dynamodbav:"Time"`
    Name   string `json:"name" dynamodbav:"Name"`
}

func main() {
    svc := dynamodb.New(session.New(), aws.NewConfig().WithRegion("ap-northeast-1"))

    input := &dynamodb.QueryInput{
        TableName: aws.String("UserName"),
        ExpressionAttributeNames: map[string]*string{
            "#ID":   aws.String("UserID"), // alias付けれたりする
            "#Date": aws.String("Date"),   // 予約語はそのままだと怒られるので置換する
            "#Name": aws.String("Name"),   // 予約語は(
        },
        ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
            ":id": { // :を付けるのがセオリーのようです
                N: aws.String("1"),
            },
        },
        KeyConditionExpression: aws.String("#ID = :id"),         // 検索条件
        ProjectionExpression:   aws.String("#ID, #Date, #Name"), // 取得カラム
        ScanIndexForward:       aws.Bool(false),                 // ソートキーのソート順(指定しないと昇順)
        Limit:                  aws.Int64(100),                  // 取得件数の指定もできる
    }

    result, err := svc.Query(input)
    if err != nil {
        fmt.Println("[Query Error]", err)
        return
    }

    users := make([]*User, 0)
    if err := dynamodbattribute.UnmarshalListOfMaps(result.Items, &users); err != nil {
        fmt.Println("[Unmarshal Error]", err)
        return
    }

    fmt.Println(result)

    j, _ := json.Marshal(users)
    fmt.Println(string(j))
}


$ go run dynamodb-query.go
{
  Count: 2,
  Items: [{
      Date: {
        S: "20171216"
      },
      UserID: {
        N: "1"
      },
      Name: {
        S: "fuga"
      }
    },{
      Date: {
        S: "20171215"
      },
      UserID: {
        N: "1"
      },
      Name: {
        S: "hoge"
      }
    }],
  ScannedCount: 2
}
[{"user_id":1,"date":"20171216","time":"","name":"fuga"},{"user_id":1,"date":"20171215","time":"","name":"hoge"}]

日付だけ指定して取得したい時は?

じゃあ日付(ソートキー)だけ指定して取得したいな〜ってなるじゃないですか。

input := &dynamodb.QueryInput{
    TableName: aws.String("UserName"),
    ExpressionAttributeNames: map[string]*string{
        "#Date": aws.String("Date"),
    },
    ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
        ":date": {
            S: aws.String("20171215"),
        },
    },
    KeyConditionExpression: aws.String("#Date = :date"),
}
ValidationException: Query condition missed key schema element: UserID

となって、できません。

→そんな時はグローバルセカンダリインデックス

GSIを使うと、パーティションキー・ソートキー以外での検索ができるようになるみたいです。

DateにGSIを張ってみます。
DynamoDB · AWS Console (1).png

これでGSIを使って検索できるようになりました。

input := &dynamodb.QueryInput{
    TableName: aws.String("UserName"),
    ExpressionAttributeNames: map[string]*string{
        "#Date": aws.String("Date"),
    },
    ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
        ":date": {
            S: aws.String("20171215"),
        },
    },
    KeyConditionExpression: aws.String("#Date = :date"),
    IndexName:              aws.String("Date-index"),
}
$ go run dynamodb-query.go
{
  Count: 1,
  Items: [{
      Date: {
        S: "20171215"
      },
      UserID: {
        N: "1"
      },
      Time: {
        S: "20171215120000"
      },
      Name: {
        S: "hoge"
      }
    }],
  ScannedCount: 1
}
[{"user_id":1,"date":"20171215","time":"20171215120000","name":"hoge"}]

ハピなる:cherry_blossom:

47
32
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
47
32