kdnakt blog

hello there.

Amazon DynamoDBのデータ型とJava SDKのAttributeValue

DynamoDBのJava SDKにあるAttributeValueクラスを操作しようとして、挙動を忘れていることが稀によくあるのでメモしておく。

 

 

[DynamoDBのデータ型とAttributeValueクラス]

DynamoDBでは、データベーステーブルに含まれる1件1件のデータを項目(item)と呼び、各項目は1つ以上の属性(attribute)から成り、属性(attribute)については、スカラ型、セット型、ドキュメント型がサポートされている。

 

docs.aws.amazon.com

 

スカラ型は以下の4つが該当する。

  • BOOL(ブール型、0または1)
  • N(数値型)
  • S(文字列型)
  • B(バイナリ型)

 

セット型は以下の3つが該当する。

  • NS(数値セット型)
  • SS(文字列セット型)
  • BS(バイナリセット型)

 

ドキュメント型はJSONのように、List形式やMap形式で入れ子になった属性の集合である。

 

今回は、N(数値型)とS(文字列型)について見ていく。

AWS SDK for Javaでは、属性(attribute)のデータ型と値をまとめたクラスとして、AttributeValueクラスが提供されている。

バージョン2.X系のAWS SDKではAttributeValue#n()またはAttributeValue#s()で属性の値を取得することができる。

また、バージョン1.X系のAWS SDKではAttributeValue#getN()またはAttributeValue#getS()で同様に属性の値を取得することができる。

どちらのSDKバージョンでも、数値型・文字列型のどちらの値を取得する場合でも、Javaの戻り値の型はStringとなっている。

 

[異なるデータ型のメソッドはnullを返す]

タイトルの通りだが、属性(attribute)のデータ型と異なるデータ型のメソッドで値を取得しようとすると、nullが返ってくる。

 

実験のため、以下のようなテーブルを用意する。

f:id:kidani_a:20201103013000p:plain

 

それぞれの項目の型は次のようになっている。

  • id:S(文字列型)
  • attr_s:S(文字列型)
  • attr_n:N(数値型)

f:id:kidani_a:20201103012715p:plain

 

バージョン2.X系のAWS SDKを利用してid=1の項目を取得しようとする場合、以下のようなコードになる。

String id = "1";
DynamoDbClient dynamodb = DynamoDbClient.builder().build();
Map<String, AttributeValue> key = new HashMap<>();
key.put("id", AttributeValue.builder().s(id).build());
GetItemRequest req = GetItemRequest.builder()
        .tableName("sample")
        .key(key)
        .build();
Map<String, AttributeValue> item = dynamodb.getItem(req).item();

// 結果出力
System.out.println("id: " + id);
System.out.println("attr_s s(): " + item.get("attr_s").s());
System.out.println("attr_s n(): " + item.get("attr_s").n());
System.out.println("attr_n s(): " + item.get("attr_n").s());
System.out.println("attr_n n(): " + item.get("attr_n").n());

 

バージョン1.X系のAWS SDKを利用してid=1の項目を取得しようとする場合、以下のようなコードになる。

String id = "1";
AmazonDynamoDB dynamodb = AmazonDynamoDBClientBuilder.defaultClient();
Map<String, AttributeValue> key = new HashMap<>();
key.put("id", new AttributeValue(id));
GetItemRequest req = new GetItemRequest()
        .withTableName("sample")
        .withKey(key);
Map<String, AttributeValue> item = dynamodb.getItem(req).getItem();

// 結果出力
System.out.println("id: " + id);
System.out.println("attr_s getS(): " + item.get("attr_s").getS());
System.out.println("attr_s getN(): " + item.get("attr_s").getN());
System.out.println("attr_n getS(): " + item.get("attr_n").getS());
System.out.println("attr_n getN(): " + item.get("attr_n").getN());

 

どちらの場合でも結果は同じだったので、バージョン2.X系の場合の結果を記載しておく。結果としては、データ型に合ったメソッドを使用しないと、nullが返ってくる。

id: 1
attr_s s(): abc
attr_s n(): null
attr_n s(): null
attr_n n(): 123

id: 2
attr_s s(): 456
attr_s n(): null
attr_n s(): null
attr_n n(): 123

// 指定された名称の属性が存在しない場合
id: 3
Exception in thread "main" java.lang.NullPointerException
        at com.kdnakt.dynamodb.App.main(App.java:23)

 

id=2のデータは、属性のデータ型がS(文字列型)でも実際の値が数値である場合に、N(数値型)のためのメソッドで取得できるかどうか、を試した。結論としては変わらず、データ型がS(文字列型)の場合にはN(数値型)のためのメソッドはnullを返す。

 

[まとめ]

  • DynamoDBの項目(item)の属性(attribute)にはスカラ型、セット型、ドキュメント型がある
  • AWS SDK for Javaでは属性のデータ型と値をまとめたAttributeValueクラスを利用できる
  • AttributeValueクラスのgetterは、実際のデータ型と異なるデータ型のものを利用するとnullが返る
  • サンプルコードは以下のリポジトリにまとめてある

バージョン2.X系のAWS SDKを利用したサンプル

バージョン1.X系のAWS SDKを利用したサンプル