Is It possible to change value of Range key in Dyn

2020-08-09 09:08发布

问题:

I know it may be a very silly question, but I am new to DynamoDB.

My doubt is is it possible to update the value of a Range Key in DynamoDB.

Suppose My Table is "TEST"

{
ID : PK/HK
Date : RK
Name : GSI 
Add : LSI
}

I want to modify Date Attribute.

Initial Values in Table was:

{
ID = "344"
Date = "5656"
Name = "ABC"
}

Running this code below. I am able to change the Name Attribute which is GSI.

Map<String,AttributeValue> item = new HashMap<String,AttributeValue>();
item.put("ID", new AttributeValue("344"));
item.put("Date", new AttributeValue("5656"));

Map<String,AttributeValueUpdate> item1 = new HashMap<String,AttributeValueUpdate>();

AttributeValueUpdate update = new AttributeValueUpdate().withValue(new AttributeValue("AMIT")).withAction("PUT");
item1.put("Name", update);


UpdateItemRequest updateItemreq = new UpdateItemRequest("Test",item,item1);
UpdateItemResult updateItemres = dynamoDBUSEast.updateItem(updateItemreq);

But When I change this line

item1.put("Name", update);

with

 item1.put("Date", update);

I am getting some error as

Exception in thread "main" com.amazonaws.AmazonServiceException: One or more parameter values were invalid: Cannot update attribute Date. This attribute is part of the key (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: HRRP24Q7C48AMD8ASAI992L6MBVV4KQNSO5AEMVJF66Q9ASUAAJG)
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:820)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:439)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:245)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:2908)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.updateItem(AmazonDynamoDBClient.java:1256)

So Is it possible to change the range Key value?

回答1:

No, like the exception message states, you Cannot update attribute Date. This attribute is part of the key.

You can also see this under the AttributeUpdates documentation:

The names of attributes to be modified, the action to perform on each, and the new value for each. If you are updating an attribute that is an index key attribute for any indexes on that table, the attribute type must match the index key type defined in the AttributesDefinition of the table description. You can use UpdateItem to update any nonkey attributes.

The documentation states that you can update any attribute for "an attribute that is an index key attribute for any indexes on that table", which means that when you update an attribute that is projected onto an index, even it is is part of that indexes key, that index will also be updated to reflect the original item.



回答2:

From the docs of AttributeValueUpdate

You cannot use UpdateItem to update any primary key attributes. Instead, you will need to delete the item, and then use PutItem to create a new item with new attributes.



回答3:

It's a little buried but in docs for UpdateItem it says: "You can use UpdateItem to update any nonkey attributes."

So, currently the only way to update the primary key of an item is to delete the old item and write a new one.



回答4:

Here is my implementation of updating id in .net by deleting the item and then recreating it with the new id. I assume java is very similar:

 // Based on https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemsExample.html
public class UpdateId
{
    private static string tableName = "MyTableName";
    private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
    private static bool isVerbose = false;

    public static void ChangeId(string currentId, string newId)
    {
        try
        {
            var deletedItem = DeleteItem(currentId);

            if (deletedItem.Count == 0)
            {
                Console.WriteLine($"ERROR: Item to delete not found: {currentId}");
                return;
            }
            deletedItem["Id"] = new AttributeValue
            {
                S = newId
            };

            CreateItem(deletedItem);
            var updatedItem = RetrieveItem(newId);
            if (updatedItem.Count > 0 && updatedItem["Id"].S == newId)
            {
                Console.WriteLine($"Item id successfully changed from ({currentId}) to ({newId})");
            }
            else
            {
                Console.WriteLine($"ERROR: Item id didn't change from ({currentId}) to ({newId})");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine("To continue, press Enter");
            Console.ReadLine();
        }
    }

    private static void CreateItem(Dictionary<string, AttributeValue> item)
    {
        var request = new PutItemRequest
        {
            TableName = tableName,
            Item = item
        };
        client.PutItem(request);
    }

    private static Dictionary<string, AttributeValue> RetrieveItem(string id)
    {
        var request = new GetItemRequest
        {
            TableName = tableName,
            Key = new Dictionary<string, AttributeValue>()
        {
            { "Id", new AttributeValue {
                  S = id
              } }
        },
            ConsistentRead = true
        };
        var response = client.GetItem(request);

        // Check the response.
        var attributeList = response.Item; // attribute list in the response.
        if (isVerbose)
        {
            Console.WriteLine("\nPrinting item after retrieving it ............");
            PrintItem(attributeList);
        }
        return attributeList;

    }

    private static Dictionary<string, AttributeValue> DeleteItem(string id)
    {
        var request = new DeleteItemRequest
        {
            TableName = tableName,
            Key = new Dictionary<string, AttributeValue>()
        {
            { "Id", new AttributeValue {
                  S = id
              } }
        },

            // Return the entire item as it appeared before the update.
            ReturnValues = "ALL_OLD",
      //      ExpressionAttributeNames = new Dictionary<string, string>()
      //  {
      //      {"#IP", "InPublication"}
      //  },
      //      ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
      //  {
      //      {":inpub",new AttributeValue {
      //           BOOL = false
      //       }}
      //  },
      //      ConditionExpression = "#IP = :inpub"
        };

        var response = client.DeleteItem(request);

        // Check the response.
        var attributeList = response.Attributes; // Attribute list in the response.
                                                 // Print item.
        if (isVerbose)
        {
            Console.WriteLine("\nPrinting item that was just deleted ............");
            PrintItem(attributeList);
        }

        return attributeList;
    }

    private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
    {
        foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
        {
            string attributeName = kvp.Key;
            AttributeValue value = kvp.Value;

            Console.WriteLine(
                attributeName + " " +
                (value.S == null ? "" : "S=[" + value.S + "]") +
                (value.N == null ? "" : "N=[" + value.N + "]") +
                (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                );
        }
        Console.WriteLine("************************************************");
    }
}

To call it just do this:

UpdateId.ChangeId("OriginalId", "NewId");