Сравнение даты и времени для условной записи в DynamoDB

В данный момент я работаю с DynamoDB. Я хочу использовать условную запись для обновления записи, если эта запись имеет дату, которая старше поля даты новой записи.

Есть ли способ сравнить типы DateTime для условной записи? Или это сейчас только для целых чисел, строк и потоков?

Спасибо.


person Francis Gilbert    schedule 05.06.2015    source источник
comment
Как вы храните дату и время? Вы используете ISO-8601 с типом данных String или используете Number с разницей во времени? (как из эпохи)?   -  person mkobit    schedule 05.06.2015
comment
@Kobit Я использую ISO-8601 со строковым типом данных (например: 2015-06-08T11: 34: 37Z). Спасибо.   -  person Francis Gilbert    schedule 08.06.2015


Ответы (2)


Поскольку вы упомянули, что используете ISO-8601 с типом данных String, легко использовать сравнение операторы (<, <= и т. д.) в вашем условном выражении из-за лексикографического порядка, описанного в этом ответе.

Вот краткий пример, в котором я использовал время Java 8 и запускал его с 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);
    }
}

И вывод:

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} }
person mkobit    schedule 08.06.2015
comment
Спасибо, рад, что нашел это. Безумие, что цвет - обязательная часть ключа. Я предположил, что это просто часть синтаксиса выражения. - person Landon Kuhn; 15.09.2016

DynamoDB не понимает даты. Если вы сохраните дату как длинную, мс / с с эпохи, вы можете использовать арифметические операции <, >= и т. Д.

Если вы используете представление String, все зависит от того, сможете ли вы найти правильный оператор DynamoDB для запроса по двум из них.

Я лично использую первое, то есть делаю это с помощью вычислений.

person Chen Harel    schedule 08.06.2015