top of page
検索

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

 
 
 

最新記事

すべて表示
コマンド整理する~Git編~

そういえば環境変わる度にメモを作ってる気がするやつ。 Web公開したらどこからでも見れるやんに今更気づきました。 ということで、自分用ですがgitのローカル操作・リモート操作でよく使う~使いそうくらいのコマンドを整理します。 ローカル操作 ローカルブランチを一覧表示 $...

 
 
 
GoでDIしたのでモック使ってテストしたかった

「タイトル日本語不自由か」というツッコミは締め切っております。 以前、GoでDIしたのですが、そもそもなんでDIしたのかというとテストコードを書きたかったからなんですよね。 それも、機能ごとに分離したテストを。 で、DIしたからにはモックも使わないといけない、どうやって使え...

 
 
 
Goでテストコード書いてみた

突然ですが、テストコード書いてますか? 私はテスト駆動に憧れているので、少なくともバックエンドの処理を書くときは書くようにしてます。(フロントは要件を整理しながら作ることもあり、あまり書けてません...。) ということで、Goでもテストコードを書いたので、ちょっとまとめてみ...

 
 
 

Comments


bottom of page