Go×DynamoDBでデータの登録・検索
- よしを
- 2023年9月26日
- 読了時間: 3分
今回はGo×DynamoDBでCRUDに挑戦!(実際にはCreateとReadとだけ)
環境
・Windows11 64bit
・Visual Studio Code 1.82.2
・Go 1.21.1
実装
今回はgureguさんという方のDynamoDB用の 結論だけ書いちゃうとこんな感じのコードになりました。
※Go×Lambdaデプロイ編の続きのコードなので、階層など知りたい方はそちらを参照してください。
package chat
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/guregu/dynamo"
)
type SendRequest struct {
RoomId string `json:"RoomId"`
Message string `json:"Message"`
}
type RecieveRequest struct {
RoomId string `json:"RoomId"`
}
type Message struct {
Id string
RoomId string
Content string
RegistAt string
}
// dynamoDBに接続する関数
func connectDynamoDB() *dynamo.DB {
dynamoDbRegion := "ap-northeast-1"
return dynamo.New(session.New(), &aws.Config{
Region: aws.String(dynamoDbRegion),
})
}
// メッセージ送信ロジック
func Send(request SendRequest) (bool, error) {
db := connectDynamoDB()
table := db.Table("Message")
uuid, err := uuid.NewUUID()
if err != nil {
fmt.Printf("Failed to generate uuid[%v]\n", err)
return &PostMessageOutput{Result: false}, err
}
message := model.Message{
Id: uuid.String(),
RoomId: event.RoomId,
Content: event.Message,
RegistAt: time.Now().Format("2006/01/02 15:04:05.000"),
}
// メッセージを登録
err = table.Put(message).Run()
if err != nil {
fmt.Printf("Failed to put item[%v]\n", err)
return false, err
}
return true, err
}
// メッセージ取得ロジック
func Recieve(event RecieveRequest) (string, error) {
db := connectDynamoDB()
table := db.Table("Message")
message := model.Message{
RoomId: event.RoomId,
RegistAt: time.Now().Format("2006/01/02 15:04:05.000"),
}
var readResult model.Message
err := table.Get("RoomId", message.RoomId).Range("RegistAt", dynamo.Less, message.RegistAt).Index("RoomId-RegistAt-index").One(&readResult)
if err != nil {
fmt.Printf("Failed to get item[%v]\n", err)
}
fmt.Printf("[%s : %s : %s]\n", readResult.Id, readResult.Content, readResult.RegistAt)
return readResult.Content, err
}
テーブル構成書かないとダメじゃん。
今回使ったのはMessageテーブルだけで、下の感じでした。
論理名 | 物理名 | 型 | キー |
メッセージID | Id | S(文字列) | Hash Key |
部屋ID | RoomId | S(文字列) | GSI (※) |
本文 | Content | S(文字列) | |
登録日時 | RegistAt | S(文字列) | Range Key |
※GSIのインデックス名はRoomId-RegistAt-index DynamoDBは基本的にキーとして設定したものでしか検索できないっぽい。
上のテーブルだと、本文に〇〇が含まれるものを取得みたいなことができない。(浅い知識だったらごめんなさい。)
Hash KeyっていうのがRDSでいうPKみたいなもので、Rage Keyっていうのが並び替えとか取得範囲を指定するときに使うもの。GSIはグローバルセカンダリインデックスの略称で、このインデックスのHash Keyに設定するとこれでも検索できるようになる。
肝心のコードの説明。
関数connectDynamoDBの中で接続するDynamoDBの設定をしています。今回はリージョンだけ設定していますが、エンドポイントとかも設定できるみたい。(DynamoDB-localを使用するときはエンドポイントとしてlocalhostを設定しました。)
で、table := db.Table("Message")でアクセスするテーブルを取得。
登録時
table.Put(message).Run()
Putの引数に登録するデータを入れるだけ。簡単。
検索時
table.Get("RoomId", message.RoomId).Range("RegistAt", dynamo.Less, message.RegistAt).Index("RoomId-RegistAt-index").One(&readResult)
GSI使ってるせいでちょっと長い...。 GetメソッドでHash Keyにあたるものを指定。今回はGSIをもとに取得したいので、RoomIdを指定。RangeメソッドにはRange Keyを設定。第二引数には第三引数を基準とした取得条件を指定する。(第三引数と一致するものだけならdynamo.Equal、第三引数より小さいもならdynamo.Lessなど。) IndexはGSIのインデックス名を指定。セカンダリインデックスではなく、普通のHash Keyで取得する場合はいらない。
最後のOneは取得件数。1件取得のメソッドなので、複数件取れるとエラーになる。複数件取りたい場合はAllとかを使うとよさそう。
分解するとそんなに難しくなかったね。
ざっくりとした説明だけど、大体こんな感じ。 大体必要なワードには触れたはずなので、興味のある方は調べてみてね。
所感
改めてコードを見返すと結構シンプル。書いてるときは割と苦労した気がするんだけど...。DdynamoDBを理解していればもっとすんなりいったんだろうなぁ。RDSを使う場合と違って向き先指定がなくてもよいのが未だに意味が分からない。どこのMessageテーブルかわかんなくない?ってなる。AWS様が良しなにやってくれているものだと強引に納得しますわ。今回分に書ききれなかったけど、Lambda×DynamoDBでも結構躓いたので、次回の記事はその辺について書きますー。
参考
https://qiita.com/Hiroki11x/items/756797b45d4461784013
Comments