DateTime Comparison for Conditional Names in DynamoDB

I am working with DynamoDB at the moment. I want to use a conditional record to update a record if that record has a date that is greater than the new record's date field.

Is there a way to compare DateTime types for conditional notation? Or is it currently only for integers, strings and streams?

Thank.

+3


source to share


2 answers


Since you mentioned that you are using ISO-8601 with a type String

, it is easy to use the comparison operators ( <

, <=

etc.) in a conditional expression because of the lexicographic ordering described in this answer .

Here's a quick example where I was using Java 8 time and running it in DynamoDB Local:

import com.google.common.collect.ImmutableMap;

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.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
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.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.util.Tables;

import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class DynamoDBStackoverflow {

    public static final String TABLE_NAME = "exampleTable";
    private static final String HASH_KEY = "hashAttributeName";

    public static void main(String[] args) {

        AWSCredentials awsCredentials = new BasicAWSCredentials("key", "secret");
        AmazonDynamoDB client = new AmazonDynamoDBClient(awsCredentials);
        client.setEndpoint("http://localhost:4000");
        DynamoDB dynamoDB = new DynamoDB(client);

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

        final CreateTableRequest createTableRequest = new CreateTableRequest()
            .withTableName(TABLE_NAME)
            .withKeySchema(new KeySchemaElement(HASH_KEY, KeyType.HASH))
            .withAttributeDefinitions(new AttributeDefinition(HASH_KEY, ScalarAttributeType.S))
            .withProvisionedThroughput(new ProvisionedThroughput(15L, 15L));
        final Table table = dynamoDB.createTable(createTableRequest);

        final Instant now = Instant.now();
        final Instant before = now.minus(10, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.MINUTES);
        final Instant after = now.plus(10, ChronoUnit.MINUTES);
        System.out.println("Before: " + before.toString());
        System.out.println("Now: " + now.toString());
        System.out.println("After: " + after.toString());

        table.putItem(new Item().withPrimaryKey(HASH_KEY, "1")
                          .withString("dateField", before.toString()));
        table.putItem(new Item().withPrimaryKey(HASH_KEY, "2")
                          .withString("dateField", now.toString()));
        System.out.println("put items");
        table.scan().forEach(System.out::println);

        UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "1")
            .withConditionExpression("dateField < :beforeDate")
            .withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
            .withUpdateExpression("SET dateField = :beforeDate");

        try {
            table.updateItem(updateItemSpec);
            throw new RuntimeException();
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("expected conditional write with < to fail when they are equal");
        }

        updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "2")
            .withConditionExpression("dateField < :beforeDate")
            .withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
            .withUpdateExpression("SET dateField = :beforeDate");

        try {
            table.updateItem(updateItemSpec);
            throw new RuntimeException();
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("expected conditional write with < to fail when new is before");
        }

        updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "1")
            .withConditionExpression("dateField <= :beforeDate")
            .withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
            .withUpdateExpression("SET dateField = :beforeDate");

        try {
            table.updateItem(updateItemSpec);
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("should not happen");
            throw new RuntimeException();
        }

        updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "2")
            .withConditionExpression("dateField <= :afterDate")
            .withValueMap(ImmutableMap.of(":afterDate", after.toString()))
            .withUpdateExpression("SET dateField = :afterDate");
        try {
            table.updateItem(updateItemSpec);
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("should not happen");
            throw new RuntimeException();
        }

        System.out.println();
        System.out.println("after all updates");
        table.scan().forEach(System.out::println);
    }
}

      



And the output is:

Before: 2015-06-08T15:57:00Z
Now: 2015-06-08T16:07:08.893Z
After: 2015-06-08T16:17:08.893Z
put items
{ Item: {hashAttributeName=1, dateField=2015-06-08T15:57:00Z} }
{ Item: {hashAttributeName=2, dateField=2015-06-08T16:07:08.893Z} }
expected conditional write with < to fail when they are equal
expected conditional write with < to fail when new is before

after all updates
{ Item: {hashAttributeName=1, dateField=2015-06-08T15:57:00Z} }
{ Item: {hashAttributeName=2, dateField=2015-06-08T16:17:08.893Z} }

      

+6


source


DynamoDB doesn't understand dates. If you keep the date that long, ms / s from the epoch, then you can use arithmetic <

, >=

etc.

If you're using a String presentation, it all depends on whether you can find the correct DynamoDB statement to query on two of them.



I personally use the former when doing it with calculus.

+1


source







All Articles