DynamoDBのJava SDKにあるAttributeValueクラスを操作しようとして、挙動を忘れていることが稀によくあるのでメモしておく。
[DynamoDBのデータ型とAttributeValueクラス]
DynamoDBでは、データベーステーブルに含まれる1件1件のデータを項目(item)と呼び、各項目は1つ以上の属性(attribute)から成り、属性(attribute)については、スカラ型、セット型、ドキュメント型がサポートされている。
スカラ型は以下の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が返ってくる。
実験のため、以下のようなテーブルを用意する。
それぞれの項目の型は次のようになっている。
- id:S(文字列型)
- attr_s:S(文字列型)
- attr_n:N(数値型)
バージョン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
を返す。