Java – dynamodbmapper saves items only when unique
I try to keep the items in the table unique according to the combination of two different columns
I have an instanceid and ImageID column (and others) based on several posts on stackoverflow and AWS forums. Should the following be valid?
public void saveUnique(Server server) { DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression(); Map<String,ExpectedAttributeValue> expectedAttributes = ImmutableMap.<String,ExpectedAttributeValue>builder() .put("instanceId",new ExpectedAttributeValue(false)) .put("imageId",new ExpectedAttributeValue(false)) .build(); saveExpression.setExpected(expectedAttributes); saveExpression.setConditionalOperator(ConditionalOperator.AND); try { mapper.save(server,saveExpression); } catch (ConditionalCheckFailedException e) { //Handle conditional check } }
However, every time I try to save a duplicate item (the same instanceid and ImageID), it will be successfully saved to the database
What did I miss here?
Edit R.E. notionquest answer
Update to the answer below
I have a job of running the API every minute The response of the API is represented as a server POJO The server has a property named instanceid
I want to make sure that if the server with this instanceid is already in the database, please do not save it
The server object has another ID attribute, which is set as the table primary key
public void saveUnique(Server server) { DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression(); Map<String,ExpectedAttributeValue> expected = new HashMap<>(); expected.put("instanceId",new ExpectedAttributeValue(new AttributeValue(server.getInstanceId())).withComparisonOperator(ComparisonOperator.NE)); saveExpression.setExpected(expected); try { mapper.save(server,saveExpression); } catch (ConditionalCheckFailedException e) { LOGGER.info("Skipped saving as not unique..."); } }
This code will save the server object again and again without throwing an exception
Server POJO
@DynamoDBTable(tableName = "Servers") public class Server { @Id private String id = UUID.randomUUID().toString(); @DynamoDBTypeConvertedJson private Task task; @DynamoDBAttribute(attributeName = "instanceId") private String instanceId; public Server() { } @DynamoDBHashKey public String getId() { return id; } // other standard getters and setters }
Solution
If I understand this correctly, you want to ensure the uniqueness of fields that are not hash keys
I'm not sure why you don't use instanceid as the hash key of the servers table. I think you have reason to do so
My answer: it seems that you can't do this without using auxiliary tables
This is your existing servers table:
+----------------------------------------------+ | Servers | +----------------------------------------------+ | * id the hash key | | * instanceId non-key field,must be unique| | | | * ... | | * other fields | | * ... | +----------------------------------------------+
I will create an additional table using instanceid as the hash key:
+----------------------------------------------+ | Instance | +----------------------------------------------+ | * instanceId the hash key | +----------------------------------------------+
With such a table, you must do this before saving records to the server. First, ensure that the instanceid value is unique by adding a record (putitem) to the instance, and provide a conditionexpression, such as attribute_ not_ exists(instanceId).
And you can continue to add records to servers only when the put operation is completed without a conditionalcheckfailedexception error
If you want to ensure the uniqueness of records in the server based on the combination of the two fields instanceid and ImageID, instead of just instanceid, use the connection values of these fields as a single field in the aux table:
+----------------------------------------------+ | Instance_Image | +----------------------------------------------+ | * instanceId_imageId the hash key | +----------------------------------------------+