Edited at

DynamoDBからデータを取得

More than 1 year has passed since last update.

こんな感じの、毎日名前が変えられる謎の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

となって、できません。


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

http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GSI.html

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: