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:
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?
Comment l'implémenteriez-vous en utilisant l'API Java?
Connaissez-vous des plans pour soutenir cela à l'avenir?
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"}}
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)
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;
}