I'm trying to figure out the best way to delete an attribute from an item in Dynamo DB. Below is what I tried, but I get an exception saying that DELETE is not a supported for either type N or S.
Exception in thread "main" Status Code: 400, AWS Service: AmazonDynamoDB, AWS Request ID: 09MRO4PVTJ8IK6OHLKSM551REJVV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ValidationException, AWS Error Message: One or more parameter values were invalid: Action DELETE is not supported for the type N
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:544)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:284)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:169)
at >com.amazonaws.services.dynamodb.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:675)
at >com.amazonaws.services.dynamodb.AmazonDynamoDBClient.updateItem(AmazonDynamoDBClient.java:371)
Key pk = new Key(new AttributeValue().withN(Long.toString(123)));
AttributeValueUpdate avu = new AttributeValueUpdate(new AttributeValue().withN("555"), "DELETE");
Map<String, AttributeValueUpdate> m = new HashMap<String, AttributeValueUpdate>();
m.put(String.valueOf(555), avu);
UpdateItemRequest uir = new UpdateItemRequest("users", pk, m);
dynamoDB.updateItem(uir);
One point of confusion is why the attribute value matters for a deletion. I really want to delete an attribute name and any associated values, but couldn't find the appropriate way to do that in the SDK.
Help would be appreciated.
I could have sworn I already tried this but by replacing the AttributeValue with a null value it works:
Key pk = new Key(new AttributeValue().withN(Long.toString(123)));
AttributeValueUpdate avu = new AttributeValueUpdate(null, "DELETE");
Map<String, AttributeValueUpdate> m = new HashMap<String, AttributeValueUpdate>();
m.put(String.valueOf(555), avu);
UpdateItemRequest uir = new UpdateItemRequest("users", pk, m);
dynamoDB.updateItem(uir);
This also works.
Table table = dynamoDB.getTable("users");
table.updateItem(new PrimaryKey("<MY HASH KEY NAME>", <MY HASH VALUE>), new AttributeUpdate("columnToRemove").delete());
or you can even use Expressions in an Item Update.
REMOVE - Removes one or more attributes from an item.
To delete an Attribute from Dynamo DB while Updating an item of the table
UpdateItemRequest updateItemRequest =new UpdateItemRequest().withTableName(tableName).withKey(key);
updateItemRequest.addAttributeUpdatesEntry("privileges",new AttributeValueUpdate()
.withAction(AttributeAction.DELETE));
updateItemRequest.addAttributeUpdatesEntry("description", new AttributeValueUpdate()
.withValue(new AttributeValue().withS("description")));
In above Example, First I removed privileges from Item and then updated description in Item.
Related
I am new in dynamo db. I am trying to update the dynamo item amt attribute using the following expression.
TransactionWriteRequest transactionWriteRequest = new TransactionWriteRequest();
HashMap<String, AttributeValue> attributeValues = new HashMap<>();
attributeValues.put(":amount", new AttributeValue().withN(amount));
// key
Map<String, AttributeValue> key = new HashMap<>();
key.put("pk", new AttributeValue().withS(pk));
key.put("sk", new AttributeValue().withS(sk));
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
.withKey(key)
.withTableName("dynamo-test")
.withUpdateExpression("SET amt = amt + :amount")
.withExpressionAttributeValues(attributeValues);
transactionWriteRequest.addUpdate(updateItemRequest);
dynamoDBMapper.transactionWrite(transactionWriteRequest);
There are multiple updates which are getting executed in transactions. On executing this, it is throwing the following exception.
AmazonDynamoDBException: The number of conditions on the keys is invalid
I am stuck here, not finding any error in the above code. Please help here.
Thanks in advance
I believe you are messing up two clients, you should not use Mapper Client if you are not mapping the data to a class object. Use the DynamoDB low level client which your instantiated to make the transaction request.
Furthermore, ensure that your table dynamo-test had a partition key of pk and sort key of sk both of type String.
Is it possible to delete all rows from a table and then update the table in a single transaction? I found this documentation: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-example.html
I tried implementing it for a single item:
productItemKey.put("test_id", new AttributeValue(String.valueOf(150)));
machine_ids.add(0, String.valueOf(newAssignments.get(150).get(0).getID()));
machine_ids.add(1, String.valueOf(newAssignments.get(150).get(1).getID()));
machine_ids.add(2, String.valueOf(newAssignments.get(150).get(2).getID()));
Map<String, AttributeValue> expressionAttributeValues = new HashMap<String, AttributeValue>();
expressionAttributeValues.clear();
expressionAttributeValues.put("test_id", new AttributeValue(String.valueOf(150)));
expressionAttributeValues.put("assignments", new AttributeValue().withSS(machine_ids));
expressionAttributeValues.put("needsMoreMachines", new AttributeValue().withBOOL(output.doesCTneedMoreMachines(150)));
Delete deleteItems = new Delete()
.withTableName("test_table")
.withKey(productItemKey);
Put markItemSold = new Put()
.withTableName("test_table")
.withItem(expressionAttributeValues);
Collection<TransactWriteItem> actions = Arrays.asList(
new TransactWriteItem().withDelete(deleteItems),
new TransactWriteItem().withPut(markItemSold));
TransactWriteItemsRequest placeOrderTransaction = new TransactWriteItemsRequest()
.withTransactItems(actions);
try {
client.transactWriteItems(placeOrderTransaction);
System.out.println("Transaction Successful");
...
But i keep getting this error:
Transaction request cannot include multiple operations on one item
You can manipulate up to 100 (separate) items in a transaction. You could only delete all rows if you have fewer than 100 rows.
The best way to bulk delete all rows is to delete the table. You cannot do that transactionally with the creation of the table again. Better to make a new table with a new name and then delete the old.
If you explained what your fundamental goals are we could give some advice.
I have a DynamoDb table with a GSI over two keys - string field 'id' (partition key) and number field 'count' (sort key).
I'm trying to work out how to run a query (not scan) via a Spring Java application using the DynamoDbEnhancedClient in the SDK on this table for the key condition expression:
#id = :idValue and #count between :minCount and :maxCount
I can build two separate QueryConditional objects for each part of this compound expression, for example:
var partitionKeyConditional = QueryConditional.keyEqualTo(Key.builder()
.partitionValue("myIdValue")
.build());
var sortKeyConditional = QueryConditional.sortBetween(Key.builder()
.sortValue(0)
.build(), Key.builder()
.sortValue(100)
.build());
But I don't know how to combine these in the actual query request:
dynamoDbEnhancedClient.table(myTableName, TableSchema.fromBean(TableObject.class))
.query(QueryEnhancedRequest.builder()
.queryConditional(SomeJoinFunction??(partitionKeyConditional, sortKeyConditional))
.build())
.items();
I can see I could use a filterExpression, but I assume this would occur after the key conditions have been applied in the query to select results, so the advantage of the sort key definition is essentially lost. It most closely resembles the functionality that I want however:
var expressionAttributeNames = new HashMap<String, String>() {{
put("#id", ID_PROPERTY_NAME);
put("#count", COUNT_PROPERTY_NAME);
}};
var expressionAttributeValues = new HashMap<String, AttributeValue>() {{
put(":idValue", AttributeValue.builder().s("myId").build());
put(":minCount", AttributeValue.builder().n("0").build());
put(":maxCount", AttributeValue.builder().n("100").build());
}};
var queryExpression = Expression.builder()
.expressionNames(expressionAttributeNames)
.expressionValues(expressionAttributeValues)
.expression("#id = :idValue and #count between :minCount and :maxCount")
.build();
I am probably missing something obvious, any suggestions?
The Key Builder used by the QueryConditionals can take both a partitionKey and sortKey value to build its expression. So when you build your QueryConditional.sortBetween object, you can define the matching partitionKey there:
var partitionKeyValue = "myIdValue"
var sortKeyConditional = QueryConditional.sortBetween(Key.builder()
.partitionValue(partitionKeyValue)
.sortValue(0)
.build(), Key.builder()
.partitionValue(partitionKeyValue)
.sortValue(100)
.build());
I am doing batchWriteItem operation on multiple tables of DynamoDb. My code is as follows -
BatchWriteItemOutcome outcome = null;
try {
TableWriteItems userTableWriteItems = new TableWriteItems("User")
.withHashAndRangeKeysToDelete("clientAccountKey", "userKey", clientAccountKey, "xyzUserKey"); // Working for this Method
TableWriteItems PosTrackingWriteItems = new TableWriteItems("PosTracking")
.withHashOnlyKeysToDelete("userKey", "xyzUserKey"); // ** Not Working for this **
outcome = dynamoDb.batchWriteItem (
userTableWriteItems,
PosTrackingWriteItems);
}
catch(Exception e){
System.out.println("Exception in Removing User Data !!! ");
e.printStackTrace();
}
If I just specify batchWrite delete withHashAndRangeKeysToDelete method where I specify Hash and Range key both, it is working.
But its not working for withHashOnlyKeysToDelete method where I specify HashKey name and HashKey Value as paramerters. I keep getting this exception:
com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: The provided key element does not match the schema. Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException.
My PosTracking table has HashKey (String) as userKey and I am passing String from the method as well. I have a GSI also in this table with name clientAccountKey (String). I tried using addHashOnlyPrimaryKeysToDelete & .addPrimaryKeyToDelete methods also for TableWriteItems but its not working either.
What is the primary key schema for the PosTracking table? Does it have a range key? If so you need to specify both the hash key and range key. DynamoDB does not allow you to delete items using just a hash key - you must specify the complete primary key including the range key.
I have an App which uses Firebase and it uses 'push' to write a record. My problem is with updating the content of that record. Any help very welcome. I am using Firebase Authentication email/password and that works fine. I also have my database in a Java Class which also works fine. In onCreate method I have the data referenced:
databasePropertyData FirebaseDatabase.getInstance().getReference("users");
Using a button I can create a new record with it's unique identifier, which is what I want:
String ownerId = databasePropertyData.push().getKey();
PropertyData propertyData = new PropertyData(ownerId, ownerName, name);
databasePropertyData.child(ownerId).setValue(propertyData);
This code works fine and creates a record with the user id just as I want.
However, I now want to update that particular record and that is where the problems lies. The code I have used (and a myriad variations) sets up a new record rather than updating the existing data. This is one example of my failed experimentation:
String ownerId = databasePropertyData.getKey();
databasePropertyData.child(ownerId).setValue(name,ownerName);
Any help would be much appreciated.
This is happening because you are using the push() method. It generates a new random key every time you are signing in. To solve this, use the uid instead of the pushed key.
PropertyData propertyData = new PropertyData(ownerId, ownerName, name);
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
databasePropertyData.child(uid).setValue(propertyData);
The benefit of using the uid is that you can update the record very easily.
databasePropertyData.child(uid).updateChildren(propertyData);
You can update specified field using updateChild, here is ref:
https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields
You have this in your database:
users
randomid
ownerId: 12345
ownerName: userx
name: anothername
To update you can do this, since you are using push(), then use the variable that has the key in it and do this:
String ownerId = databasePropertyData.push().getKey(); //the variable that has the key, not a new variable
PropertyData propertyData = new PropertyData(ownerId, ownerName, name);
databasePropertyData.child(ownerId).setValue(propertyData);
Or instead of this, you can change the database structure and use user id:
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
PropertyData propertyData = new PropertyData(ownerId, ownerName, name);
databasePropertyData.child(ownerId).setValue(propertyData);
Or you can make a query and retrieve the push() key from the database and update the values in the query.
But you have to update all 3 fields.
String ownerId = databasePropertyData.getKey();
here instead of creating new ownerId, you should use the same Id of the propertyData that you want to update. Then using updateChildren or setValue method, you can update the value.
Then this will work fine:
databasePropertyData = FirebaseDatabase.getInstance().getReference("users");
PropertyData propertyData = new PropertyData(ownerId, ownerName, name);
databasePropertyData.child(ownerId).setValue(propertyData);