ブログはじめました(仮)

飽きずに続けばタイトル変更します。見習いエンジニアですが、備忘録的に色々と書いてみたいと思います。

Amazon DynamoDBをrubyで触ってみる 第2弾〜update_item〜

前回に引き続きDynamoDBrubyでゴニョゴニョしてみました。

今回は、ドキュメントを読んで(個人的に)わかりづらかったupdate_itemについてです。

update_itemというのは、その名の通り「すでに登録してあるアイテムに変更を加える操作」です。
オプションに、PUT・ADD・DELETEというのを指定するのですが、その使い分けをまとめてみました。

まず、アトリビュート(カラムに相当)の型の種類を理解しておく必要があります。
全部で6種類あります。

タイプ 説明
N 数字
S 文字列
B バイナリ
NS 数字の配列
SS 文字列の配列
BS バイナリの配列

続いて、PUT,ADD,DELETEの違いについてです。

PUT 問答無用でそのアトリビュートを置き換え。存在しなければアトリビュートごと作る
ADD 型がNのときは、足し算。型がセット(NS,SS,BS)のときは、配列に追加
DELETE 型がN,S,Bのときは、そのアトリビュートを削除。セットのときは、その要素のみを削除

となります。


それでは実際に試してみたいと思います。

まずはテーブルを作ってアイテムを保存します。

require 'rubygems'
require 'aws-sdk'
require './init.rb'

dynamoClient = AWS::DynamoDB::Client.new({
  :dynamo_db_endpoint => 'dynamodb.ap-northeast-1.amazonaws.com',
  :access_key_id => ACCESS,
  :secret_access_key => SECRET})

dynamoClient.create_table(
  :table_name => TABLE,
  :key_schema => {:hash_key_element => {:attribute_name => "id",
                                        :attribute_type => "N"}},
  :provisioned_throughput => {:read_capacity_units => 2,
                              :write_capacity_units => 2}
)

sleep 20

dynamoClient.put_item(
  :table_name => TABLE,
  :item => {
    "id" => {:n => "1"},
    "put" => {:n => "1"},
    "add" => {:n => "1"},
    "delete" => {:n => "1"}
  }
)

dynamoClient.put_item(
  :table_name => TABLE,
  :item => {
    "id" => {:n => "2"},
    "put" => {:ns => ["1","2","3"]},
    "add" => {:ns => ["1","2","3"]},
    "delete" => {:ns => ["1","2","3"]}
  }
)

続いて、アップデートを実行します。

require 'rubygems'
require 'aws-sdk'
require './init.rb'

dynamoClient = AWS::DynamoDB::Client.new({
  :dynamo_db_endpoint => 'dynamodb.ap-northeast-1.amazonaws.com',
  :access_key_id => ACCESS,
  :secret_access_key => SECRET})

init = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  }
)

p init

#PUT
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  },
  :attribute_updates => {
    "put" => {
      :value => {:n => "100"},
      :action => "PUT"
    }
  },
)

put = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  }
)

p put

#ADD
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  },
  :attribute_updates => {
    "add" => {
      :value => {:n => "100"},
      :action => "ADD"
    }
  },
)

add = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  }
)

p add

#DELETE
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  },
  :attribute_updates => {
    "delete" => {
      :value => {:n => "100"},
      :action => "DELETE"
    }
  },
)

delete = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  }
)

p delete
{"Item"=>{"id"=>{"N"=>"1"}, "add"=>{"N"=>"1"}, "put"=>{"N"=>"1"}, "delete"=>{"N"=>"1"}}, "ConsumedCapacityUnits"=>0.5}
{"Item"=>{"id"=>{"N"=>"1"}, "add"=>{"N"=>"1"}, "put"=>{"N"=>"100"}, "delete"=>{"N"=>"1"}}, "ConsumedCapacityUnits"=>0.5}
{"Item"=>{"id"=>{"N"=>"1"}, "add"=>{"N"=>"101"}, "put"=>{"N"=>"100"}, "delete"=>{"N"=>"1"}}, "ConsumedCapacityUnits"=>0.5}
/Users/tetsuyam/.rvm/gems/ruby-1.9.3-p385/gems/aws-sdk-1.10.0/lib/aws/core/client.rb:360:in `return_or_raise': One or more parameter values were invalid: Action DELETE is not supported for the type N (AWS::DynamoDB::Errors::ValidationException)
	from /Users/tetsuyam/.rvm/gems/ruby-1.9.3-p385/gems/aws-sdk-1.10.0/lib/aws/core/client.rb:461:in `client_request'
	from (eval):3:in `update_item'
	from updateItem1-2.rb:66:in `<main>'

PUTのときは、1→100。ADDのときは、1→101となることが確認できます。
DELETEだとエラーがでます。
タイプがNのときのDELETEでは、アトリビュートの値を指定する必要がないようです。(むしろ指定したらダメ)

#DELETE
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "1"}
  },
  :attribute_updates => {
    "delete" => {
      :value => {:n => "100"},
      :action => "DELETE"
    }
  },
)

とすると

{"Item"=>{"add"=>{"N"=>"101"}, "id"=>{"N"=>"1"}, "put"=>{"N"=>"100"}}, "ConsumedCapacityUnits"=>0.5}

となり、うまくいきました。



次に、SET型の場合を試したいと思います。

require 'rubygems'
require 'aws-sdk'
require './init.rb'

dynamoClient = AWS::DynamoDB::Client.new({
  :dynamo_db_endpoint => 'dynamodb.ap-northeast-1.amazonaws.com',
  :access_key_id => ACCESS,
  :secret_access_key => SECRET})

init = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  }
)

p init

#PUT
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  },
  :attribute_updates => {
    "put" => {
      :value => {:ns => ["100"]},
      :action => "PUT"
    }
  },
)

put = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  }
)

p put

#ADD
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  },
  :attribute_updates => {
    "add" => {
      :value => {:ns => ["100"]},
      :action => "ADD"
    }
  },
)

add = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  }
)

p add

#DELETE
dynamoClient.update_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  },
  :attribute_updates => {
    "delete" => {
      :value => {:ns => ["1"]},
      :action => "DELETE"
    }
  },
)

delete = dynamoClient.get_item(
  :table_name => TABLE,
  :key => {
    :hash_key_element => {:n => "2"}
  }
)

p delete
|ruby|<


>||
{"Item"=>{"id"=>{"N"=>"2"}, "add"=>{"NS"=>["3", "100", "2", "1"]}, "put"=>{"N"=>"100"}, "delete"=>{"NS"=>["3", "2", "1"]}}, "ConsumedCapacityUnits"=>0.5}
{"Item"=>{"id"=>{"N"=>"2"}, "add"=>{"NS"=>["3", "2", "1"]}, "put"=>{"NS"=>["100"]}, "delete"=>{"NS"=>["3", "2","1"]}}, "ConsumedCapacityUnits"=>0.5}
{"Item"=>{"id"=>{"N"=>"2"}, "add"=>{"NS"=>["3", "100", "2", "1"]}, "put"=>{"NS"=>["100"]}, "delete"=>{"NS"=>["3", "2", "1!]}}, "ConsumedCapacityUnits"=>0.5}
{"Item"=>{"id"=>{"N"=>"2"}, "add"=>{"NS"=>["3", "100", "2", "1"]}, "put"=>{"NS"=>["100"]}, "delete"=>{"NS"=>["3", "2"]}}, "ConsumedCapacityUnits"=>0.5}

PUTでは置き換え、ADDでは追加、DELETEでは削除されていることがわかります。


ADDで足し算できるのは、カウントするときとかに便利そうですね。