2

I'm brand new to DynamoDB and finding it surprising how "model driven" a schema-less database can be. Anyway, petty snarkiness out of the way, I am wondering how to declare a property in an item which will be an array of values but one which CAN have duplicate values.

Specifically what I'm storing is wordcloud array of emotive words and if a particular word is used more than once then I want to know that. My simple answer was to have an attribute/property called wordsPositive which would be set as type "SS" but it appears this will not allow for duplicate array elements.

The error I get when trying is:

400: Input collection [better, excellent, best, important, good, success, best, creative, powerful, benefits] contains duplicates.]

Looking at the AWS web interface at a record which did not have duplicates I can see that the structure defined could support duplicated values but given that its calling the list a "set" my guess is that this just isn't allowed:

aws web interface

What is the best way of doing this in DynamoDB?

2
  • Oh, I also tried the "L" type as well ... also didn't work Commented Jan 25, 2015 at 19:17
  • You can't have duplicate data in a set docs.oracle.com/javase/6/docs/api/java/util/Set.html. Consider implementing it as a comma separated string and have a marshalling class to seperate it Commented Nov 17, 2015 at 10:39

1 Answer 1

2

The "L" data type is what you are looking for. Here is a full example I ran against DynamoDBLocal using AWS Java SDK version 1.9.3. There is an immediate Scan to check the results of the table (output below code). It should not be any different when using the actual DynamoDB service:

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import com.amazonaws.services.dynamodbv2.util.Tables;
import com.google.common.collect.ImmutableList;

import java.util.List;

public class Test28140400 {

    private static final String TABLE_NAME = "test_table";
    private static final String HASH_KEY_ATTRIBUTE_NAME = "hash";
    private static final String RANGE_KEY_ATTRIBUTE_NAME = "range";

    public static void main(String[] args) {
        AWSCredentials awsCredentials = new BasicAWSCredentials("key", "secret");
        AmazonDynamoDB dynamoDB = new AmazonDynamoDBClient(awsCredentials);
        dynamoDB.setEndpoint("http://localhost:4000");

        if (Tables.doesTableExist(dynamoDB, TABLE_NAME)) {
            dynamoDB.deleteTable(TABLE_NAME);
        }

        CreateTableRequest createTableRequest = new CreateTableRequest();
        createTableRequest.setTableName(TABLE_NAME);
        createTableRequest.setProvisionedThroughput(new ProvisionedThroughput(50l, 50l));

        List<KeySchemaElement> keySchema = ImmutableList.<KeySchemaElement>builder()
                .add(new KeySchemaElement(HASH_KEY_ATTRIBUTE_NAME, KeyType.HASH))
                .add(new KeySchemaElement(RANGE_KEY_ATTRIBUTE_NAME, KeyType.RANGE))
                .build();
        createTableRequest.setKeySchema(keySchema);

        List<AttributeDefinition> attributeDefinitions = ImmutableList.<AttributeDefinition>builder()
              .add(new AttributeDefinition(HASH_KEY_ATTRIBUTE_NAME, ScalarAttributeType.S))
              .add(new AttributeDefinition(RANGE_KEY_ATTRIBUTE_NAME, ScalarAttributeType.N))
              .build();
        createTableRequest.setAttributeDefinitions(attributeDefinitions);

        CreateTableResult createTableResult = dynamoDB.createTable(createTableRequest);
        Tables.waitForTableToBecomeActive(dynamoDB, TABLE_NAME);

        PutItemRequest putItemRequest = new PutItemRequest();
        putItemRequest.setTableName(TABLE_NAME);
        putItemRequest.addItemEntry(HASH_KEY_ATTRIBUTE_NAME, new AttributeValue().withS("first_hash"));
        putItemRequest.addItemEntry(RANGE_KEY_ATTRIBUTE_NAME, new AttributeValue().withN("123456789"));
        // Using the "L" type
        //better, excellent, best, important, good, success, best, creative, powerful, benefits
        List<AttributeValue> attributes = ImmutableList.<AttributeValue>builder()
                .add(new AttributeValue().withS("better"))
                .add(new AttributeValue().withS("excellent"))
                .add(new AttributeValue().withS("best"))
                .add(new AttributeValue().withS("important"))
                .add(new AttributeValue().withS("good"))
                .add(new AttributeValue().withS("success"))
                .add(new AttributeValue().withS("best"))
                .add(new AttributeValue().withS("creative"))
                .add(new AttributeValue().withS("powerful"))
                .add(new AttributeValue().withS("benefits"))
                .build();
        putItemRequest.addItemEntry("random_attribute", new AttributeValue().withL(attributes));
        dynamoDB.putItem(putItemRequest);

        ScanResult scan = dynamoDB.scan(new ScanRequest(TABLE_NAME));
        scan.getItems().forEach(System.out::println);
    }
}

Output:

{random_attribute={L: [{S: better,}, {S: excellent,}, {S: best,}, {S: important,}, {S: good,}, {S: success,}, {S: best,}, {S: creative,}, {S: powerful,}, {S: benefits,}],}, range={N: 123456789,}, hash={S: first_hash,}}

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Mike. I had tried the 'L' type and got an error message which I unfortunately didn't write down but I had thought it had similar text to what I was getting on SS. I've found DynamoDB so frustrating that I decided to just live with a file based JSON solution for now. :^p
@ken It is definitely a cool platform that takes some learning to get used to. Like in the example I provided, it is pretty easy to just try some stuff in the [DynamoDBLocal ](docs.aws.amazon.com/amazondynamodb/latest/developerguide/…) if you want to test out some things before trying them against the service!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.