こんな感じの、毎日名前が変えられる謎のUserNameテーブルがあるとします。
パーティションキーとソートキー
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にしたりして遊んでます。
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
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を使うと、パーティションキー・ソートキー以外での検索ができるようになるみたいです。
これで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"}]