Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I handle an empty java set of strings in AWS DynamoDB

I'm trying to store an array of strings within an AWS DynamoDB table. For the most part this array will be populated with at least one string. However there is the case where the array could be empty.

I've created a DynamoDB model in a Java Lambda function that has a set of strings as one of it's properties. If I try to save a DynamoDB model when the set of strings is empty it gives me an error saying I can't store an empty set in DynamoDB.

So my question is, how would handle removing that set property when it's empty from my model before I save / update it in the DynamoDB?

Here's an example of the model.

@DynamoDBTable(tableName = "group")
public class Group {
    private String _id;
    private Set<String> users;

    @Null
    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey
    public String getId() {
        return _id;
    }

    public void setId(final String id) {
        _id = id;
    }

    @DynamoDBAttribute
    public Set<String> getUsers(){
        return users;
    }

    public void setUsers(final Set<String> users) {
        this.users = users;
    }

    public void addUser(String userId) {
        if(this.users == null){
            this.setUsers(new HashSet<String>(Arrays.asList(userId)));
        }else{
            this.getUsers().add(userId);
        }
   }
}

First time when I will create a group. It could have no user, or it could have one or more user.

like image 974
James Parker Avatar asked Apr 28 '16 14:04

James Parker


People also ask

Does DynamoDB support empty strings?

Amazon DynamoDB now supports empty values for non-key String and Binary attributes in DynamoDB tables. Amazon DynamoDB now supports empty values for non-key String and Binary attributes in DynamoDB tables.

Does DynamoDB accept null values?

Dynamodb can't accept a key with an explicitly NULL value.

What is string set in DynamoDB?

DynamoDB supports types that represent sets of number, string, or binary values. All the elements within a set must be of the same type. For example, an attribute of type Number Set can only contain numbers; String Set can only contain strings; and so on.

How does DynamoDB store data in Java?

Select Dynamo DB and then in Access Level section select GetItem and PutItem. Select Resources. Click on Add ARN. Fill Region where your Dynamo Db table is and enter name of your table and click Add.


2 Answers

This is somewhat of an old question but the way I would solve this problem is with a custom DynamoDBMarshaller.

Making use of the @DynamoDBMarshalling annotation, you can decorate the POJO accessor methods in order to dictate to the DynamoDB mapper which marshaller class to use to serialize and deserialize the set of strings. This way you get control over the special use cases.

Here is also a link to an AWS blog post with an example

The one caveat with the approach above is the customer marshaller solution serializes and deserializes to/from string so the representation in the database wouldn't be a set per se. However, I wouldn't consider that to be too bad.

Another approach might be to use the Document API, instead of the object mappers, which gives you full control over the items. Though I would still go for custom mapper with string backing.

like image 101
Mike Dinescu Avatar answered Oct 04 '22 04:10

Mike Dinescu


When it came down to the actual problem it was because the code I inherited had the SaveBehavior on the DynamoDBMapperConfig set to UPDATE_SKIP_NULL_ATTRIBUTES which skips null values and therefore will never remove them from DynamoDB. See this post of explanations of all the different save behaviors. https://java.awsblog.com/post/Tx1MH3BFPW8FX6W/Using-the-SaveBehavior-Configuration-for-the-DynamoDBMapper

To elaborate on this a little bit further.

I'm setting my DynamoDBMapperConfig.SaveBehavior as such within my JAVA project.

_dynamoDBMapperConfig = new DynamoDBMapperConfig.Builder() .withSaveBehavior(SaveBehavior.UPDATE) .withTableNameResolver(TABLE_NAME_RESOLVER) .withConversionSchema(ConversionSchemas.V2) .build();

Then whenever you update a model that has a mapped @DynamoDBAttribute you also need to set the particular value to (null).

user.setFirstName(null)

This was the easiest way I found to be able to remove attributes from a DynamoDB Entry.

like image 42
James Parker Avatar answered Oct 04 '22 03:10

James Parker