Go
AWS
DynamoDB

あえて aws-sdk-go で dynamoDB を使うときの基本操作

More than 3 years have passed since last update.


始めに注意

最初に言っておきますが、goからawsのdynamoDBをいじるなら

色々良いフレームワークが他に作られています。

気楽にDynamoDBを使おうgureguさんは


aws-sdk-goでは、DynamoDBへの問い合わせはできるが、かなり面倒臭いことをやらなきゃいけない。公式のライブラリーはポインターだらけで、データのMarshalとUnmarshalで苦労することがあります。


と言っていますが本当にその通りです。

それでも何かしらの理由があって aws-sdk-go で書かなきゃいけない場合もあるかもしれないので

そういう場合にだけ使って下さい。

あと、文章が真面目なのはここまでです。


DynamoDBの使い方


公式の情報

github は https://github.com/aws/aws-sdk-go やね。

公式ドキュメントは ココ見たらいいね。


インストールとか

おなじみ

go get github.com/aws/aws-sdk-go

だけやね。

import は



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

みたいな感じかな。

まぁ、IDE使ってたら補完してくれるでしょ。

あと、認証情報が必要なんで、IAMで良い感じのロールをあてたユーザーを作って、

~/.aws/credentials


[default]
aws_access_key_id = AKID1234567890
aws_secret_access_key = MY-SECRET-KEY

みたいなファイルを作ったらいいよ。

この辺はdynamoDB以外でも同じなので情報出てくるからいいね。

windowsユーザー?ごめん。知らない。

コードに直接書くことも出来るぽいけど、危ないからやめてね。


 兎にも角にも dynamodb インスタンスを作る

とは言っても一行



ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

こんだけやね。

WithRegion()の中身は使ってるリージョンを指定してね。

東京ならap-northeast-1ね。他は公式のこのページで確認したらいいよ。


テーブル生成

一番シンプルに作るならこんな感じ


main.go



package main

import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"fmt"
)

func main() {
ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

params := &dynamodb.CreateTableInput{
AttributeDefinitions: []*dynamodb.AttributeDefinition{
{
AttributeName: aws.String("id"), // プライマリキー名
AttributeType: aws.String("S"), // データ型(String:S, Number:N, Binary:B の三種)
},
},
KeySchema: []*dynamodb.KeySchemaElement{
{
AttributeName: aws.String("id"), // インデックス名
KeyType: aws.String("HASH"), // インデックスの型(HASH または RANGE)
},
},
ProvisionedThroughput: &dynamodb.ProvisionedThroughput{ // Required
ReadCapacityUnits: aws.Int64(1), // 読み込みキャパシティーユニット(デフォルト:1)
WriteCapacityUnits: aws.Int64(1), // 書き込みキャパシティーユニット(デフォルト:1)
},
TableName: aws.String("TableName"), // テーブル名
}

resp, err := ddb.CreateTable(params)

if err != nil {
fmt.Println(err.Error()) // エラー処理
}

fmt.Println(resp)
}


awsにデータとして渡す時は基本 aws.String() とか、型に合わせてしてやればOKかな。

AttributeType とか KeyType とか、なんで string を渡す仕様になってるのかは不明。

だけどまぁそういうものってことで。

セカンダリインデックスとか、ストリームとか設定できるけど、

そんなことしたい人は多分公式ドキュメント読むだろうからカット。


テーブル削除

作ったテーブルを消すのは一瞬で、


main.go



package main

import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"fmt"
)

func main() {
ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

params := &dynamodb.DeleteTableInput{
TableName: aws.String("TableName"), // 削除するテーブルの名前
}

resp, err := ddb.DeleteTable(params)

if err != nil {
fmt.Println(err.Error()) // エラー処理
}

fmt.Println(resp)
}


まぁ消すだけやし簡単なのは当然やね。


データを入れる

(ここからはテーブル生成で作ったテーブルがある前提)

データベースなんだからデータ入れないと始まらんね。


main.go



package main

import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"fmt"
)

func main() {
ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

param := &dynamodb.UpdateItemInput{
TableName: aws.String("TableName"), // テーブル名を指定

Key: map[string]*dynamodb.AttributeValue{
"id": {
S: aws.String("foo"), // キー名を指定
},
},

ExpressionAttributeNames: map[string]*string{
"#username": aws.String("username"), // 項目名をプレースホルダに入れる
},
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":username_value": {
S: aws.String("hoge"), // 値をプレースホルダに入れる
},
},
UpdateExpression: aws.String("set #username = :username_value"), //プレースホルダを利用して更新の式を書く

//あとは返してくる情報の種類を指定する
ReturnConsumedCapacity: aws.String("NONE"),
ReturnItemCollectionMetrics: aws.String("NONE"),
ReturnValues: aws.String("NONE"),
}

resp, err := ddb.UpdateItem(param) //実行

if err != nil {
fmt.Println(err.Error())
}

fmt.Println(resp)
}


ってやると

2016_03_15_17_11.jpg

データ入ってるね。

返してくる情報の種類とその指定する文字列については、DynamoDBメモ (+PHP SDK2) っていう記事を書いてくれている人がいる。

PHP だけど値は一緒だからこっち参照したら良いって思う。

値の入れ方は UpdateExpression を使うと良いって前に読んだ。

(参考(外部サイト): DynamoDBのupdateItemを、AttributeUpdatesではなくUpdateExpressionで行う)

UpdateExpression() で使える式は公式のココに載ってるからこっちで確認。

これでデータも入って、データベース始まったね。


データの更新

データを入れる時と同じ方法で、



Key: map[string]*dynamodb.AttributeValue{
"id": {
S: aws.String("foo"), // キー名を指定
},
},

の部分のキーを既存のキーにしたら上書きできるからそれだけやね。


データの検索

検索っていってもまずは一致するプライマリキーを取り出してくるくらいでいいよね。


main.go



package main

import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"fmt"
)

func main() {
ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

params := &dynamodb.GetItemInput{
TableName: aws.String("TableName"), // テーブル名

Key: map[string]*dynamodb.AttributeValue{
"id": { // キー名
S: aws.String("foo"), // 持ってくるキーの値
},
},
AttributesToGet: []*string{
aws.String("username"), // 欲しいデータの名前
},
ConsistentRead: aws.Bool(true), // 常に最新を取得するかどうか

//返ってくるデータの種類
ReturnConsumedCapacity: aws.String("NONE"),
}

resp, err := ddb.GetItem(params)

if err != nil {
fmt.Println(err.Error())
}

//resp.Item[項目名].型 でデータへのポインタを取得
fmt.Println(*resp.Item["username"].S)
}


複雑なことしなければこの程度だから言うほどそんなに面倒じゃないんじゃないかな。

最後のデータの取り出しが、型をくっつける + ポインタで返ってくる でちょっと面倒?

まぁ慣れればそんなでもないね。


削除

単純に消すだけならやっぱりキー名だけで OK やね。


main.go



package main

import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"fmt"
)

func main() {
ddb := dynamodb.New(session.New(), aws.NewConfig().WithRegion("us-east-1"))

params := &dynamodb.DeleteItemInput{
TableName: aws.String("TableName"), // テーブル名

Key: map[string]*dynamodb.AttributeValue{
"id": { // キー名
S: aws.String("foo"), // 削除するキーの値
},
},

//返ってくるデータの種類
ReturnConsumedCapacity: aws.String("NONE"),
ReturnItemCollectionMetrics: aws.String("NONE"),
ReturnValues: aws.String("NONE"),
}

_, err := ddb.DeleteItem(params)

if err != nil {
fmt.Println(err.Error())
}
}


とっても単純。

セカンダリキーとか色々設定してるとちょっと面倒っぽいけど、

とりあえずこれくらい出来れば十分やね。


まとめ

最初に脅し入れた割にはそんなに難しい感じにはならんかったね。

ただ、マップとかリストとか扱い始めると面倒(難しくは無いけど)だから、

やっぱり使えるなら他のフレームワークとか使った方がいいね。