【问题标题】:Update specific attribute using UpdateItemEnhancedRequest DynamoDb java sdk2使用 UpdateItemEnhancedRequest DynamoDb java sdk2 更新特定属性
【发布时间】:2021-02-02 13:31:22
【问题描述】:

我们有一个 DynamoDB 表,它有一个属性计数器,它会根据一个事件由多个 lambda 异步递减。我正在尝试使用 UpdateItemEnhancedRequest 更新计数器(使用 Dynamodb 增强客户端。- JAVA SDK 2)。我能够建立更新计数器的条件,但它会更新整个项目而不仅仅是计数器。有人可以指导如何使用 DynamoDb 增强客户端更新单个属性吗?

代码示例

    public void update(String counter, T item) {

    AttributeValue value = AttributeValue.builder().n(counter).build();

    Map<String, AttributeValue> expressionValues = new HashMap<>();
    expressionValues.put(":value", value);

    Expression myExpression = Expression.builder()
            .expression("nqctr = :value")
            .expressionValues(expressionValues)
            .build();

    UpdateItemEnhancedRequest<T> updateItemEnhancedRequest =
            UpdateItemEnhancedRequest.builder(collectionClassName)
                    .item(item)
                    .conditionExpression(myExpression)
                    .build();

    getTable().updateItem(updateItemEnhancedRequest);

    }

【问题讨论】:

    标签: amazon-web-services amazon-dynamodb


    【解决方案1】:

    更新特定列时,需要指定要更新的列。假设我们有这张表:

    现在假设我们要更新 archive 列。您需要在代码中指定列。这里我们将key对应的item的archive列改为Closed(单列更新)。请注意,我们使用名为 updatedValuesHashMap 对象指定列名。

    // Archives an item based on the key
    public String archiveItem(String id){
            DynamoDbClient ddb = getClient();
    
            HashMap<String,AttributeValue> itemKey = new HashMap<String,AttributeValue>();
            itemKey.put("id", AttributeValue.builder()
                    .s(id)
                    .build());
    
            HashMap<String, AttributeValueUpdate> updatedValues =
                    new HashMap<String,AttributeValueUpdate>();
    
            // Update the column specified by name with updatedVal
            updatedValues.put("archive", AttributeValueUpdate.builder()
                    .value(AttributeValue.builder()
                            .s("Closed").build())
                    .action(AttributeAction.PUT)
                    .build());
    
            UpdateItemRequest request = UpdateItemRequest.builder()
                    .tableName("Work")
                    .key(itemKey)
                    .attributeUpdates(updatedValues)
                    .build();
    
            try {
                ddb.updateItem(request);
                return"The item was successfully archived";
    

    注意:这不是增强型客户端。

    此代码来自 AWS 教程,该教程展示了如何使用 Spring Boot 构建 Java Web 应用程序。完整教程在这里:

    Creating the DynamoDB web application item tracker

    要使用增强型客户端更新单个列,请致电 Table method。这将返回一个DynamoDbTable instance。现在您可以调用 updateItem 方法了。

    以下是使用增强型客户端更新 archive 列的逻辑。注意你得到一个 Work 对象,调用它的 setArchive 然后传递 Work 对象。 workTable.updateItem(r->r.item(work));

    Java 代码:

      // Update the archive column by using the Enhanced Client.
        public String archiveItemEC(String id) {
    
            DynamoDbClient ddb = getClient();
    
            try {
    
                DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                        .dynamoDbClient(getClient())
                        .build();
    
                DynamoDbTable<Work> workTable = enhancedClient.table("Work", TableSchema.fromBean(Work.class));
    
                //Get the Key object.
                Key key = Key.builder()
                        .partitionValue(id)
                        .build();
    
                // Get the item by using the key.
                Work work = workTable.getItem(r->r.key(key));
                work.setArchive("Closed");
    
                workTable.updateItem(r->r.item(work));
                return"The item was successfully archived";
            } catch (DynamoDbException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
            return "";
        }
    

    此答案显示了更新 DynamoDB 表中单个列的两种方法。上面的教程现在展示了这种方式。

    【讨论】:

    • 感谢您的快速回复!我能够使用 DynamoDbClient 进行更新,但由于我们在项目中使用的是 DynamoDbEnhancedClient,因此我发现使用 DynamoDbEnhancedClient 的行为相同。
    • 我正在考虑更新本教程以使用 DynamoDbEnhancedClient 来更新该列。
    • DynamoDbEnhancedClient updateItem 方法将 UpdateItemEnhancedRequest 作为输入,在 UpdateItemEnhancedRequest 上,我无法像为 UpdateItemRequest 那样找到 attributeUpdates 方法。有什么方法可以做到这一点?
    • 查看新逻辑 - 这是一种更加面向对象的方法。您获取对象,更改值(即 - 调用 setArchive())然后在调用 updateItem 时传递 Work 对象。
    • 如果我想根据某些条件更新存档列,例如仅当该项目的集合中的值关闭时才将存档更新为打开。在哪里可以使用表达式设置该条件?
    【解决方案2】:

    在您的原始解决方案中,您误解了 conditionExpression 属性的含义。这用于验证与键匹配的项目必须为真才能执行更新的条件,而不是执行更新本身的表达式。

    有一种方法可以使用增强型客户端执行此操作,而无需在进行更新之前获取对象。 UpdateItemEnhancedRequest 类有一个 ignoreNulls attribute,它将从更新中排除所有空属性。默认情况下这是false,这会导致对象被完全覆盖。

    假设这是您的项目的结构(没有所有增强的客户端注释和样板,您可以添加它们):

    class T {
      public String partitionKey;
      public Int counter;
      public String someOtherAttribute
    
      public T(String partitionKey) {
        this.partitionKey = partitionKey;
        this.counter = null;
        this.someOtherAttribute = null
      }
    }
    

    你可以只更新计数器,并且只有当项目存在时,像这样:

    public void update(Int counter, String partitionKey) {
        T updateItem = new T(partitionKey)
        updateItem.counter = counter
    
        Expression itemExistsExpression = Expression.builder()
                .expression("attribute_exists(partitionKey)")
                .build();
    
        UpdateItemEnhancedRequest<T> updateItemEnhancedRequest =
                UpdateItemEnhancedRequest.builder(collectionClassName)
                        .item(item)
                        .conditionExpression(itemExistsExpression)
                        .ignoreNulls(true)
                        .build();
    
        getTable().updateItem(updateItemEnhancedRequest);
    }
    

    【讨论】:

    • 请注意ignoreNulls(true)。开发人员在编写新代码时很容易会忽略空字段这一事实,这可能会导致错误。即使您的方法不仅仅是update(T item),如果有人像update(null, "mykey") 这样传递null,即使上面的示例也可能会令人困惑:那将没有效果。可以说,参数应该是 int 而不是 Integer 所以它是不可为空的。
    猜你喜欢
    • 2022-11-18
    • 1970-01-01
    • 2018-02-17
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    相关资源
    最近更新 更多