新しい AWS DynamoDBドキュメントAPI は、基になるJSON表現に直接対応する2つの新しいデータ型を許可します:Map(別名JSONオブジェクト)とList(別名JSON配列)。
ただし、これらのデータ型の属性を完全に上書きせずに更新する方法はありません。対照的に、Number属性は別の数値を追加することで更新できるため、Javaでは、次のようなことができます。
new AttributeUpdate("Some numeric attribute").addNumeric(17);
同様に、 addElements をSetデータ型の属性に指定できます。 (古いAPIでは、両方の目的でAttributeAction.ADDを使用していました。)
しかし、マップまたはリストの場合、以前の値をローカルで更新してから、その値の代わりにそれをPUTする必要があるようです(Javaなど)。
List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);
これは読みにくくなり、状況によっては効率が低下します。
だから私の質問は:
以前の値を上書きせずにマップまたはリストのデータ型の属性を更新する方法はありますか?たとえば、要素をリストに追加したり、要素をマップに配置したりするには、
Java APIを使用してどのように実装しますか?
これを将来サポートする計画を知っていますか?
pdateItem API のUpdateExpressionをご覧ください。
たとえば、リスト付きのアイテムがあるとします。
{
"hashkey": {"S" : "my_key"},
"my_list" : {"L":
[{"N":"3"},{"N":"7"} ]
}
次のようなコードでリストを更新できます。
UpdateItemRequest request = new UpdateItemRequest();
request.setTableName("myTableName");
request.setKey(Collections.singletonMap("hashkey",
new AttributeValue().withS("my_key")));
request.setUpdateExpression("list_append(:prepend_value, my_list)");
request.setExpressionAttributeValues(
Collections.singletonMap(":prepend_value",
new AttributeValue().withN("1"))
);
dynamodb.updateItem(request);`
また、list_append式の引数の順序を逆にして、リストに追加することもできます。
次のような式:SET user.address.zipcode = :Zip
は、式の属性値と組み合わせたJSONマップ要素をアドレス指定します{":Zip" : {"N":"12345"}}
DynamoDBの例に基づき、これも機能します(scala)
val updateItemSpec:UpdateItemSpec = new UpdateItemSpec()
.withPrimaryKey("hashkey", my_key)
.withUpdateExpression("set my_list = list_append(:prepend_value, my_list)")
.withValueMap(new ValueMap()
.withList(":prepend_value", "1"))
.withReturnValues(ReturnValue.UPDATED_NEW)
println("Updating the item...")
val outcome: UpdateItemOutcome = table.updateItem(updateItemSpec)
println("UpdateItem succeeded:\n" + outcome.getItem.toJSONPretty)
キーと値のペアを追加または更新するための汎用関数。属性updateColumn
はマップタイプである必要があります。
Update tableName
属性名は、key:value
ペアの下でattributeName
として渡す必要があります。primaryKey= primaryKeyValue
public boolean insertKeyValue(String tableName, String primaryKey, String
primaryKeyValue, String attributeName, String newKey, String newValue) {
//Configuration to connect to DynamoDB
Table table = dynamoDB.getTable(tableName);
boolean insertAppendStatus = false;
try {
//Updates when map is already exist in the table
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey(primaryKey, primaryKeyValue)
.withReturnValues(ReturnValue.ALL_NEW)
.withUpdateExpression("set #columnName." + newKey + " = :columnValue")
.withNameMap(new NameMap().with("#columnName", attributeName))
.withValueMap(new ValueMap().with(":columnValue", newValue))
.withConditionExpression("attribute_exists("+ attributeName +")");
table.updateItem(updateItemSpec);
insertAppendStatus = true;
//Add map column when it's not exist in the table
} catch (ConditionalCheckFailedException e) {
HashMap<String, String> map = new HashMap<>();
map.put(newKey, newValue);
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey(primaryKey,primaryKeyValue)
.withReturnValues(ReturnValue.ALL_NEW)
.withUpdateExpression("set #columnName = :m")
.withNameMap(new NameMap().with("#columnName", attributeName))
.withValueMap(new ValueMap().withMap(":m", map));
table.updateItem(updateItemSpec);
insertAppendStatus = true;
} catch(Exception e) {
e.printStackTrace();
}
return insertAppendStatus;
}