web-dev-qa-db-ja.com

AWS DynamoDBドキュメントAPIでマップまたはリストを更新するにはどうすればよいですか?

新しい 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);

これは読みにくくなり、状況によっては効率が低下します。

だから私の質問は:

  1. 以前の値を上書きせずにマップまたはリストのデータ型の属性を更新する方法はありますか?たとえば、要素をリストに追加したり、要素をマップに配置したりするには、

  2. Java APIを使用してどのように実装しますか?

  3. これを将来サポートする計画を知っていますか?

14
Roy Fox

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"}}

13
Ben Schwartz

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)
6
Ivan Gonzalez

キーと値のペアを追加または更新するための汎用関数。属性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;
}
0