Как обновить карту или список в API документов AWS DynamoDB?
Новый документ API AWS DynamoDB позволяет использовать два новых типа данных, которые непосредственно соответствуют базовому представлению JSON: Map (объект JSON) и List (массив JSON).
Однако я не могу найти способ обновить атрибуты этих типов данных без их полной перезаписи. В отличие от этого, атрибут Number можно обновить, добавив другое число, поэтому в Java вы можете сделать что-то вроде:
new AttributeUpdate("Some numeric attribute").addNumeric(17);
Точно так же вы можете добавить элементы к атрибуту типа данных Set. (В старом API вы использовали бы AttributeAction.ADD для обеих целей.)
Но для карты или списка кажется, что вы должны обновить предыдущее значение локально, а затем поставить его вместо этого значения, например, в Java:
List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);
Это гораздо менее читабельно и при некоторых обстоятельствах гораздо менее эффективно.
Итак, мои вопросы:
Есть ли способ обновить атрибут типа данных Map или List без перезаписи предыдущего значения? Например, добавить элемент в список или поместить элемент на карту?
Как бы вы реализовали это с помощью Java API?
Вы знаете о планах поддержать это в будущем?
2 ответа
Пожалуйста, посмотрите на UpdateExpression в API UpdateItem
Например, дан элемент со списком:
{
"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
должен быть типа map.
Обновить tableName
имя атрибута должно быть передано как attributeName
под key:value
пары, где 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;
}