如何在 AWS DynamoDB 文档 API 上更新地图或列表?
How to update a Map or a List on AWS DynamoDB document API?
新的 AWS DynamoDB document API 允许直接对应底层 JSON 表示的 2 种新数据类型:Map(又名 JSON 对象)和 List(又名 JSON 数组).
但是,我找不到一种方法来更新这些数据类型的属性而不完全覆盖它们。相反,可以通过添加另一个数字来更新数字属性,因此在 Java 中,您可以执行以下操作:
new AttributeUpdate("Some numeric attribute").addNumeric(17);
同样,您可以 addElements 设置数据类型的属性。 (在旧的 API 中,您将使用 AttributeAction.ADD 来实现这两个目的。)
但是对于 Map 或 List,似乎你必须在本地更新以前的值,然后用 PUT 代替那个值,例如 Java:
List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);
这可读性差得多,在某些情况下效率也低得多。
所以我的问题是:
有没有办法在不覆盖先前值的情况下更新 Map 或 List 数据类型的属性?例如,将元素添加到 List,或将元素放入 Map?
您将如何使用 Java API 实现它?
你知道未来有支持这个的计划吗?
请查看 UpdateItem 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)
添加或更新 key/value 对的通用函数。属性 updateColumn
应该是地图类型。
更新 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;
}
新的 AWS DynamoDB document API 允许直接对应底层 JSON 表示的 2 种新数据类型:Map(又名 JSON 对象)和 List(又名 JSON 数组).
但是,我找不到一种方法来更新这些数据类型的属性而不完全覆盖它们。相反,可以通过添加另一个数字来更新数字属性,因此在 Java 中,您可以执行以下操作:
new AttributeUpdate("Some numeric attribute").addNumeric(17);
同样,您可以 addElements 设置数据类型的属性。 (在旧的 API 中,您将使用 AttributeAction.ADD 来实现这两个目的。)
但是对于 Map 或 List,似乎你必须在本地更新以前的值,然后用 PUT 代替那个值,例如 Java:
List<String> list = item.getList("Some list attribute");
list.add("new element");
new AttributeUpdate("Some list attribute").put(list);
这可读性差得多,在某些情况下效率也低得多。
所以我的问题是:
有没有办法在不覆盖先前值的情况下更新 Map 或 List 数据类型的属性?例如,将元素添加到 List,或将元素放入 Map?
您将如何使用 Java API 实现它?
你知道未来有支持这个的计划吗?
请查看 UpdateItem 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)
添加或更新 key/value 对的通用函数。属性 updateColumn
应该是地图类型。
更新 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;
}