web-dev-qa-db-fra.com

Comment mettre à jour une carte ou une liste sur l'API de document AWS DynamoDB?

Le nouveau AWS DynamoDB document API autorise 2 nouveaux types de données qui correspondent directement à la représentation JSON sous-jacente: Map (alias JSON object) et List (alias JSON array).

Cependant, je ne peux pas trouver un moyen de mettre à jour les attributs de ces types de données sans les écraser complètement. En revanche, un attribut Number peut être mis à jour en AJOUTANT un autre numéro, donc dans Java vous pouvez faire quelque chose comme:

new AttributeUpdate("Some numeric attribute").addNumeric(17);

De même, vous pouvez addElements à un attribut d'un type de données Set. (Dans l'ancienne API, vous utilisiez AttributeAction.ADD dans les deux cas.)

Mais pour une carte ou une liste, il semble que vous devez mettre à jour la valeur précédente localement, puis la mettre à la place de cette valeur, par exemple en Java:

List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);

Ceci est beaucoup moins lisible et, dans certaines circonstances, beaucoup moins efficace.

Mes questions sont donc:

  1. Existe-t-il un moyen de mettre à jour un attribut d'un type de données Map ou List sans écraser la valeur précédente? Par exemple, pour ajouter un élément à une liste ou pour placer un élément dans une carte?

  2. Comment l'implémenteriez-vous en utilisant l'API Java?

  3. Connaissez-vous des plans pour soutenir cela à l'avenir?

14
Roy Fox

Veuillez jeter un œil à UpdateExpression dans pdateItem API

Par exemple, étant donné un élément avec une liste:

{
    "hashkey": {"S" : "my_key"},
    "my_list" : {"L": 
        [{"N":"3"},{"N":"7"} ]
}

Vous pouvez mettre à jour la liste avec un code comme celui-ci:

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);`

Vous pouvez également ajouter à la liste en inversant l'ordre des arguments dans l'expression list_append.

Une expression comme: SET user.address.zipcode = :Zip adresserait un élément de carte JSON combiné avec des valeurs d'attribut d'expression {":Zip" : {"N":"12345"}}

13
Ben Schwartz

Basé sur des exemples DynamoDB, cela fonctionne également (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

Une fonction générique pour ajouter ou mettre à jour une paire clé/valeur. l'attribut updateColumn doit être de type map.

Le nom d'attribut de mise à jour tableName doit être passé en tant que attributeName sous key:value paires où 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
Muhammad Soliman