AllIsHackedOff

Just a memo, just a progress

GoでDynamoDBのUpdateItemを呼ぶ場合の例

DynamoDBの更新は2種類存在する

  • PutItem

    Creates a new item, or replaces an old item with a new item. If an item that has the same primary key as the new item already exists in the specified table, the new item completely replaces the existing item. You can perform a conditional put operation (add a new item if one with the specified primary key doesn't exist), or replace an existing item if it has certain attribute values. You can return the item's attribute values in the same operation, using the ReturnValues parameter.
    Putはリソースの完全な置き換えを意味する。HTTPのPutと同じ意味合いだ。

  • UpdateItem

    Edits an existing item's attributes, or adds a new item to the table if it does not already exist. You can put, delete, or add attribute values. You can also perform a conditional update on an existing item (insert a new attribute name-value pair if it doesn't exist, or replace an existing name-value pair if it has certain expected attribute values).
    You can also return the item's attribute values in the same UpdateItem operation using the ReturnValues parameter.
    一方でupdateは存在しない要素の追加、条件付きアップデートなどを意味する。 サービス内のデータを「更新」したいときは基本的には差分更新を示すので、こちらの意味合いになる。

参考

DynamoDBのputItemとupdateItemの違い | ハックノート

guregu/dynamodbを使う

気楽にDynamoDBを使おう - Qiitaにあるようにaws-sdk-goを利用するとよくわからない記法でUpdate文を作ることになり「こんなことするために生まれてきたわけではないのに」的な気分に落とし込まれる。guregu氏のライブラリを用いることで直感的にDynamoDBを操作できる。

Updateを実行するためには下記のメソッドでUpdate構造体を生成するのだが、ノリでコーディングしていると引数として何を与えれればいいかワカラナイ…

func (table Table) Update(hashKey string, value interface{}) *Update {

だめな例として

## { "id" : 1, "msg": "Maimi love"} を {"id": 1, "msg": "Kamiko Love"} に書き換えたいとする
## idをHash Key (Primary Key)とする
m.msg = "Kamiko"
u := tbl.Update(strconv.Itoa(m.id, msg) 

### ValidationException: One of the required keys was not given a value

そもそもPrimary KeyがStringじゃなきゃ駄目なのかよ???みたいな疑問が湧いたり等し、ぐぐってexampleを探すも見つからずに時間を浪費する的なことになるので一旦updateItemの公式の記法に当たります。 UpdateItem - Amazon DynamoDB

### Sample Requestより抜粋
{
    "TableName": "Thread",
    "Key": {
        "ForumName": {
            "S": "Amazon DynamoDB"
        },
        "Subject": {
            "S": "Maximum number of items?"
        }
    },
    "UpdateExpression": "set LastPostedBy = :val1",
    "ConditionExpression": "LastPostedBy = :val2",
    "ExpressionAttributeValues": {
        ":val1": {"S": "alice@example.com"},
        ":val2": {"S": "fred@example.com"}
    },
    "ReturnValues": "ALL_NEW"
}      

ということでKeyに対してUpdateしたい値を与えていけば更新することができそうな予感がします。 guregu/dynamoDBにおいてはupdate構造遺体の生成時に1つのキーに対して何かしらの interface{}を割り当てているのでこの記法は使えなそう?

ということで公式の別の例を見ます。

{
    "TableName": "Thread",
    "Key": {
        "ForumName": {
            "S": "Amazon DynamoDB"
        },
        "Subject": {
            "S": "A question about updates"
        }
    },
    "UpdateExpression": "set Replies = Replies + :num",
    "ExpressionAttributeValues": { 
        ":num": {"N": "1"}
    },
    "ReturnValues" : "NONE"
}

UpateExpressionとExpressionAttributeValuesを与えてやることでConditional Updateができるようです。 Guregu/dynamoDBではupdate.go - guregu/dynamo - SourcegraphこのあたりのメソッドでUpdateExpressionを生成していることを鑑みて、よしなに生成されるように書けばよさそうです。

u := tbl.Update("id", m.id)
u.Set("msg", m.msg)
err := u.Run() 

こんな感じに書くことでうまくUpdateできるようです 尚、手元での動作確認には

が便利です。