DynamoDB conditional update based on partial nested object





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















I'm trying to partially update an item based on the attribute value of a nested object, but I not able to get it working because the condition is checking the whole nested object and not just the attribute I'm interested in.



My schema looks like this:




{
hash: hash_1,
sort: sort_1,
timestamp: 2018-11-16T00:00:00Z
A: {
value: 1,
audit: U1
}
}

I need to update timestamp and the whole A object if and only if the new timestamp is bigger and the new A.value is different from the current A.value; but without caring for A.audit.



My current approach looks like:



private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
.withTableName(TABLE_NAME)
.addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
.addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
.addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
.withValue(new AttributeValue()
.addMEntry(VALUE, new AttributeValue().withN(value))
.addMEntry(AUDIT, new AttributeValue().withS(audit)))
.withAction(AttributeAction.PUT))
.addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withAction(AttributeAction.PUT))
.addExpectedEntry(dataName, new ExpectedAttributeValue()
.withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
.withComparisonOperator(ComparisonOperator.NE))
.addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withComparisonOperator(ComparisonOperator.LT));
ddb.updateItem(updateItemRequest);


I have tried using expression and attribute values but get an exception that those cannot be combined (I'd like to avoid only using expressions as I think they are hard to read).



I have also found this question: Update nested map dynamodb, which seems to suggest that using expressions work (have not yest tested it myself).



So is it possible to have that behavior without using expressions?





My test case class (failing test is shouldNotUpdateDataIfSame):



package sandbox;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
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.UpdateItemRequest;
import org.junit.Before;
import org.junit.Test;

import static com.amazonaws.util.DateUtils.formatISO8601Date;
import static com.amazonaws.util.DateUtils.parseISO8601Date;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;

public class Sandbox {

private static final String TABLE_NAME = "Tabla";
private static final String HASH_KEY = "hash";
private static final String SORT_KEY = "sort";
private static final String TIMESTAMP = "timestamp";
private static final String VALUE = "value";
private static final String AUDIT = "audit";

private static final String HASH_KEY_1 = "hash_1";
private static final String SORT_KEY_1 = "sort_1";

private static final String DATA_A = "A";
private static final String DATA_B = "B";
private static final String VALUE_1 = "1";
private static final String VALUE_2 = "2";
private static final String USER_1 = "U1";
private static final String USER_2 = "U2";

private static AmazonDynamoDB create() {
AmazonDynamoDB dynamoDB = DynamoDBEmbedded.create().amazonDynamoDB();
CreateTableRequest createTableRequest = new CreateTableRequest()
.withTableName(TABLE_NAME)
.withKeySchema(
new KeySchemaElement(HASH_KEY, KeyType.HASH),
new KeySchemaElement(SORT_KEY, KeyType.RANGE))
.withAttributeDefinitions(
new AttributeDefinition(HASH_KEY, ScalarAttributeType.S),
new AttributeDefinition(SORT_KEY, ScalarAttributeType.S))
.withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
dynamoDB.createTable(createTableRequest);
return dynamoDB;
}

private void save(final String dataName, final String value, final String audit, final Date timestamp) {
try {
insertNewRecord(dataName, value, audit, timestamp);
} catch (ConditionalCheckFailedException e) {
try {
insertNewData(dataName, value, audit, timestamp);
} catch (ConditionalCheckFailedException e2) {
try {
updateData(dataName, value, audit, timestamp);
} catch (ConditionalCheckFailedException e3) {
// Ignore: Obsolete data or same as before
}
}
}
}

private void insertNewRecord(final String dataName, final String value, final String audit, final Date timestamp) {
PutItemRequest putItemRequest = new PutItemRequest()
.withTableName(TABLE_NAME)
.addItemEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
.addItemEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
.addItemEntry(dataName, new AttributeValue()
.addMEntry(VALUE, new AttributeValue().withN(value))
.addMEntry(AUDIT, new AttributeValue().withS(audit)))
.addItemEntry(TIMESTAMP, new AttributeValue()
.withS(formatISO8601Date(timestamp)))
.addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue().withExists(false));
ddb.putItem(putItemRequest);
}

private void insertNewData(final String dataName, final String value, final String audit, final Date timestamp) {
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
.withTableName(TABLE_NAME)
.addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
.addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
.addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
.withValue(new AttributeValue()
.addMEntry(VALUE, new AttributeValue().withN(value))
.addMEntry(AUDIT, new AttributeValue().withS(audit)))
.withAction(AttributeAction.PUT))
.addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withAction(AttributeAction.PUT))
.addExpectedEntry(dataName, new ExpectedAttributeValue().withExists(false))
.addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withComparisonOperator(ComparisonOperator.LT));
ddb.updateItem(updateItemRequest);
}

private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
.withTableName(TABLE_NAME)
.addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
.addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
.addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
.withValue(new AttributeValue()
.addMEntry(VALUE, new AttributeValue().withN(value))
.addMEntry(AUDIT, new AttributeValue().withS(audit)))
.withAction(AttributeAction.PUT))
.addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withAction(AttributeAction.PUT))
.addExpectedEntry(dataName, new ExpectedAttributeValue()
.withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
.withComparisonOperator(ComparisonOperator.NE))
.addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
.withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
.withComparisonOperator(ComparisonOperator.LT));
ddb.updateItem(updateItemRequest);
}

private Map<String, AttributeValue> get() {
GetItemRequest getItemRequest = new GetItemRequest()
.withTableName(TABLE_NAME)
.addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
.addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1));
return ddb.getItem(getItemRequest).getItem();
}

private AmazonDynamoDB ddb;

@Before
public void before() {
ddb = create();
}

@Test
public void shouldInsertNewRecord() {
Date now = new Date();
save(DATA_A, VALUE_1, USER_1, now);
Map<String, AttributeValue> item = get();
assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
assertThat(item.get(DATA_A).getM().get(AUDIT).getS(), is(equalTo(USER_1)));
assertThat(item.get(DATA_B), is(nullValue()));
}

@Test
public void shouldInsertNewData() {
Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
save(DATA_A, VALUE_1, USER_1, yesterday);
Date now = new Date();
save(DATA_B, VALUE_2, USER_1, now);
Map<String, AttributeValue> item = get();
assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
assertThat(item.get(DATA_B).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
}

@Test
public void shouldNotUpdateIfNewerExists() {
Date now = new Date();
save(DATA_A, VALUE_1, USER_1, now);
save(DATA_B, VALUE_2, USER_1, now);
Map<String, AttributeValue> item = get();
assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
}

@Test
public void shouldUpdateDataIfDifferent() {
Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
save(DATA_A, VALUE_1, USER_1, yesterday);
Date now = new Date();
save(DATA_A, VALUE_2, USER_1, now);
Map<String, AttributeValue> item = get();
assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
}

@Test
public void shouldNotUpdateDataIfSame() {
Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
save(DATA_A, VALUE_1, USER_1, yesterday);
Date now = new Date();
save(DATA_A, VALUE_1, USER_2, now);
Map<String, AttributeValue> item = get();
assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(yesterday)));
}
}









share|improve this question































    1















    I'm trying to partially update an item based on the attribute value of a nested object, but I not able to get it working because the condition is checking the whole nested object and not just the attribute I'm interested in.



    My schema looks like this:




    {
    hash: hash_1,
    sort: sort_1,
    timestamp: 2018-11-16T00:00:00Z
    A: {
    value: 1,
    audit: U1
    }
    }

    I need to update timestamp and the whole A object if and only if the new timestamp is bigger and the new A.value is different from the current A.value; but without caring for A.audit.



    My current approach looks like:



    private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
    UpdateItemRequest updateItemRequest = new UpdateItemRequest()
    .withTableName(TABLE_NAME)
    .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
    .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
    .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
    .withValue(new AttributeValue()
    .addMEntry(VALUE, new AttributeValue().withN(value))
    .addMEntry(AUDIT, new AttributeValue().withS(audit)))
    .withAction(AttributeAction.PUT))
    .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withAction(AttributeAction.PUT))
    .addExpectedEntry(dataName, new ExpectedAttributeValue()
    .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
    .withComparisonOperator(ComparisonOperator.NE))
    .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withComparisonOperator(ComparisonOperator.LT));
    ddb.updateItem(updateItemRequest);


    I have tried using expression and attribute values but get an exception that those cannot be combined (I'd like to avoid only using expressions as I think they are hard to read).



    I have also found this question: Update nested map dynamodb, which seems to suggest that using expressions work (have not yest tested it myself).



    So is it possible to have that behavior without using expressions?





    My test case class (failing test is shouldNotUpdateDataIfSame):



    package sandbox;

    import java.time.Instant;
    import java.time.temporal.ChronoUnit;
    import java.util.Date;
    import java.util.Map;

    import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
    import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
    import com.amazonaws.services.dynamodbv2.model.AttributeAction;
    import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
    import com.amazonaws.services.dynamodbv2.model.AttributeValue;
    import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
    import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
    import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
    import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
    import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
    import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
    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.UpdateItemRequest;
    import org.junit.Before;
    import org.junit.Test;

    import static com.amazonaws.util.DateUtils.formatISO8601Date;
    import static com.amazonaws.util.DateUtils.parseISO8601Date;
    import static org.hamcrest.CoreMatchers.equalTo;
    import static org.hamcrest.CoreMatchers.is;
    import static org.hamcrest.CoreMatchers.nullValue;
    import static org.hamcrest.MatcherAssert.assertThat;

    public class Sandbox {

    private static final String TABLE_NAME = "Tabla";
    private static final String HASH_KEY = "hash";
    private static final String SORT_KEY = "sort";
    private static final String TIMESTAMP = "timestamp";
    private static final String VALUE = "value";
    private static final String AUDIT = "audit";

    private static final String HASH_KEY_1 = "hash_1";
    private static final String SORT_KEY_1 = "sort_1";

    private static final String DATA_A = "A";
    private static final String DATA_B = "B";
    private static final String VALUE_1 = "1";
    private static final String VALUE_2 = "2";
    private static final String USER_1 = "U1";
    private static final String USER_2 = "U2";

    private static AmazonDynamoDB create() {
    AmazonDynamoDB dynamoDB = DynamoDBEmbedded.create().amazonDynamoDB();
    CreateTableRequest createTableRequest = new CreateTableRequest()
    .withTableName(TABLE_NAME)
    .withKeySchema(
    new KeySchemaElement(HASH_KEY, KeyType.HASH),
    new KeySchemaElement(SORT_KEY, KeyType.RANGE))
    .withAttributeDefinitions(
    new AttributeDefinition(HASH_KEY, ScalarAttributeType.S),
    new AttributeDefinition(SORT_KEY, ScalarAttributeType.S))
    .withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
    dynamoDB.createTable(createTableRequest);
    return dynamoDB;
    }

    private void save(final String dataName, final String value, final String audit, final Date timestamp) {
    try {
    insertNewRecord(dataName, value, audit, timestamp);
    } catch (ConditionalCheckFailedException e) {
    try {
    insertNewData(dataName, value, audit, timestamp);
    } catch (ConditionalCheckFailedException e2) {
    try {
    updateData(dataName, value, audit, timestamp);
    } catch (ConditionalCheckFailedException e3) {
    // Ignore: Obsolete data or same as before
    }
    }
    }
    }

    private void insertNewRecord(final String dataName, final String value, final String audit, final Date timestamp) {
    PutItemRequest putItemRequest = new PutItemRequest()
    .withTableName(TABLE_NAME)
    .addItemEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
    .addItemEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
    .addItemEntry(dataName, new AttributeValue()
    .addMEntry(VALUE, new AttributeValue().withN(value))
    .addMEntry(AUDIT, new AttributeValue().withS(audit)))
    .addItemEntry(TIMESTAMP, new AttributeValue()
    .withS(formatISO8601Date(timestamp)))
    .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue().withExists(false));
    ddb.putItem(putItemRequest);
    }

    private void insertNewData(final String dataName, final String value, final String audit, final Date timestamp) {
    UpdateItemRequest updateItemRequest = new UpdateItemRequest()
    .withTableName(TABLE_NAME)
    .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
    .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
    .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
    .withValue(new AttributeValue()
    .addMEntry(VALUE, new AttributeValue().withN(value))
    .addMEntry(AUDIT, new AttributeValue().withS(audit)))
    .withAction(AttributeAction.PUT))
    .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withAction(AttributeAction.PUT))
    .addExpectedEntry(dataName, new ExpectedAttributeValue().withExists(false))
    .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withComparisonOperator(ComparisonOperator.LT));
    ddb.updateItem(updateItemRequest);
    }

    private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
    UpdateItemRequest updateItemRequest = new UpdateItemRequest()
    .withTableName(TABLE_NAME)
    .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
    .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
    .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
    .withValue(new AttributeValue()
    .addMEntry(VALUE, new AttributeValue().withN(value))
    .addMEntry(AUDIT, new AttributeValue().withS(audit)))
    .withAction(AttributeAction.PUT))
    .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withAction(AttributeAction.PUT))
    .addExpectedEntry(dataName, new ExpectedAttributeValue()
    .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
    .withComparisonOperator(ComparisonOperator.NE))
    .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
    .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
    .withComparisonOperator(ComparisonOperator.LT));
    ddb.updateItem(updateItemRequest);
    }

    private Map<String, AttributeValue> get() {
    GetItemRequest getItemRequest = new GetItemRequest()
    .withTableName(TABLE_NAME)
    .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
    .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1));
    return ddb.getItem(getItemRequest).getItem();
    }

    private AmazonDynamoDB ddb;

    @Before
    public void before() {
    ddb = create();
    }

    @Test
    public void shouldInsertNewRecord() {
    Date now = new Date();
    save(DATA_A, VALUE_1, USER_1, now);
    Map<String, AttributeValue> item = get();
    assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
    assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
    assertThat(item.get(DATA_A).getM().get(AUDIT).getS(), is(equalTo(USER_1)));
    assertThat(item.get(DATA_B), is(nullValue()));
    }

    @Test
    public void shouldInsertNewData() {
    Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
    save(DATA_A, VALUE_1, USER_1, yesterday);
    Date now = new Date();
    save(DATA_B, VALUE_2, USER_1, now);
    Map<String, AttributeValue> item = get();
    assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
    assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
    assertThat(item.get(DATA_B).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
    }

    @Test
    public void shouldNotUpdateIfNewerExists() {
    Date now = new Date();
    save(DATA_A, VALUE_1, USER_1, now);
    save(DATA_B, VALUE_2, USER_1, now);
    Map<String, AttributeValue> item = get();
    assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
    assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
    }

    @Test
    public void shouldUpdateDataIfDifferent() {
    Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
    save(DATA_A, VALUE_1, USER_1, yesterday);
    Date now = new Date();
    save(DATA_A, VALUE_2, USER_1, now);
    Map<String, AttributeValue> item = get();
    assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
    assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
    }

    @Test
    public void shouldNotUpdateDataIfSame() {
    Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
    save(DATA_A, VALUE_1, USER_1, yesterday);
    Date now = new Date();
    save(DATA_A, VALUE_1, USER_2, now);
    Map<String, AttributeValue> item = get();
    assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(yesterday)));
    }
    }









    share|improve this question



























      1












      1








      1








      I'm trying to partially update an item based on the attribute value of a nested object, but I not able to get it working because the condition is checking the whole nested object and not just the attribute I'm interested in.



      My schema looks like this:




      {
      hash: hash_1,
      sort: sort_1,
      timestamp: 2018-11-16T00:00:00Z
      A: {
      value: 1,
      audit: U1
      }
      }

      I need to update timestamp and the whole A object if and only if the new timestamp is bigger and the new A.value is different from the current A.value; but without caring for A.audit.



      My current approach looks like:



      private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue()
      .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
      .withComparisonOperator(ComparisonOperator.NE))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);


      I have tried using expression and attribute values but get an exception that those cannot be combined (I'd like to avoid only using expressions as I think they are hard to read).



      I have also found this question: Update nested map dynamodb, which seems to suggest that using expressions work (have not yest tested it myself).



      So is it possible to have that behavior without using expressions?





      My test case class (failing test is shouldNotUpdateDataIfSame):



      package sandbox;

      import java.time.Instant;
      import java.time.temporal.ChronoUnit;
      import java.util.Date;
      import java.util.Map;

      import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
      import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
      import com.amazonaws.services.dynamodbv2.model.AttributeAction;
      import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
      import com.amazonaws.services.dynamodbv2.model.AttributeValue;
      import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
      import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
      import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
      import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
      import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
      import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
      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.UpdateItemRequest;
      import org.junit.Before;
      import org.junit.Test;

      import static com.amazonaws.util.DateUtils.formatISO8601Date;
      import static com.amazonaws.util.DateUtils.parseISO8601Date;
      import static org.hamcrest.CoreMatchers.equalTo;
      import static org.hamcrest.CoreMatchers.is;
      import static org.hamcrest.CoreMatchers.nullValue;
      import static org.hamcrest.MatcherAssert.assertThat;

      public class Sandbox {

      private static final String TABLE_NAME = "Tabla";
      private static final String HASH_KEY = "hash";
      private static final String SORT_KEY = "sort";
      private static final String TIMESTAMP = "timestamp";
      private static final String VALUE = "value";
      private static final String AUDIT = "audit";

      private static final String HASH_KEY_1 = "hash_1";
      private static final String SORT_KEY_1 = "sort_1";

      private static final String DATA_A = "A";
      private static final String DATA_B = "B";
      private static final String VALUE_1 = "1";
      private static final String VALUE_2 = "2";
      private static final String USER_1 = "U1";
      private static final String USER_2 = "U2";

      private static AmazonDynamoDB create() {
      AmazonDynamoDB dynamoDB = DynamoDBEmbedded.create().amazonDynamoDB();
      CreateTableRequest createTableRequest = new CreateTableRequest()
      .withTableName(TABLE_NAME)
      .withKeySchema(
      new KeySchemaElement(HASH_KEY, KeyType.HASH),
      new KeySchemaElement(SORT_KEY, KeyType.RANGE))
      .withAttributeDefinitions(
      new AttributeDefinition(HASH_KEY, ScalarAttributeType.S),
      new AttributeDefinition(SORT_KEY, ScalarAttributeType.S))
      .withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
      dynamoDB.createTable(createTableRequest);
      return dynamoDB;
      }

      private void save(final String dataName, final String value, final String audit, final Date timestamp) {
      try {
      insertNewRecord(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e) {
      try {
      insertNewData(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e2) {
      try {
      updateData(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e3) {
      // Ignore: Obsolete data or same as before
      }
      }
      }
      }

      private void insertNewRecord(final String dataName, final String value, final String audit, final Date timestamp) {
      PutItemRequest putItemRequest = new PutItemRequest()
      .withTableName(TABLE_NAME)
      .addItemEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addItemEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addItemEntry(dataName, new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .addItemEntry(TIMESTAMP, new AttributeValue()
      .withS(formatISO8601Date(timestamp)))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue().withExists(false));
      ddb.putItem(putItemRequest);
      }

      private void insertNewData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue().withExists(false))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);
      }

      private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue()
      .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
      .withComparisonOperator(ComparisonOperator.NE))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);
      }

      private Map<String, AttributeValue> get() {
      GetItemRequest getItemRequest = new GetItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1));
      return ddb.getItem(getItemRequest).getItem();
      }

      private AmazonDynamoDB ddb;

      @Before
      public void before() {
      ddb = create();
      }

      @Test
      public void shouldInsertNewRecord() {
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      assertThat(item.get(DATA_A).getM().get(AUDIT).getS(), is(equalTo(USER_1)));
      assertThat(item.get(DATA_B), is(nullValue()));
      }

      @Test
      public void shouldInsertNewData() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_B, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      assertThat(item.get(DATA_B).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
      }

      @Test
      public void shouldNotUpdateIfNewerExists() {
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_1, now);
      save(DATA_B, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      }

      @Test
      public void shouldUpdateDataIfDifferent() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_A, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
      }

      @Test
      public void shouldNotUpdateDataIfSame() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_2, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(yesterday)));
      }
      }









      share|improve this question
















      I'm trying to partially update an item based on the attribute value of a nested object, but I not able to get it working because the condition is checking the whole nested object and not just the attribute I'm interested in.



      My schema looks like this:




      {
      hash: hash_1,
      sort: sort_1,
      timestamp: 2018-11-16T00:00:00Z
      A: {
      value: 1,
      audit: U1
      }
      }

      I need to update timestamp and the whole A object if and only if the new timestamp is bigger and the new A.value is different from the current A.value; but without caring for A.audit.



      My current approach looks like:



      private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue()
      .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
      .withComparisonOperator(ComparisonOperator.NE))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);


      I have tried using expression and attribute values but get an exception that those cannot be combined (I'd like to avoid only using expressions as I think they are hard to read).



      I have also found this question: Update nested map dynamodb, which seems to suggest that using expressions work (have not yest tested it myself).



      So is it possible to have that behavior without using expressions?





      My test case class (failing test is shouldNotUpdateDataIfSame):



      package sandbox;

      import java.time.Instant;
      import java.time.temporal.ChronoUnit;
      import java.util.Date;
      import java.util.Map;

      import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
      import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
      import com.amazonaws.services.dynamodbv2.model.AttributeAction;
      import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
      import com.amazonaws.services.dynamodbv2.model.AttributeValue;
      import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
      import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
      import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
      import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
      import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
      import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
      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.UpdateItemRequest;
      import org.junit.Before;
      import org.junit.Test;

      import static com.amazonaws.util.DateUtils.formatISO8601Date;
      import static com.amazonaws.util.DateUtils.parseISO8601Date;
      import static org.hamcrest.CoreMatchers.equalTo;
      import static org.hamcrest.CoreMatchers.is;
      import static org.hamcrest.CoreMatchers.nullValue;
      import static org.hamcrest.MatcherAssert.assertThat;

      public class Sandbox {

      private static final String TABLE_NAME = "Tabla";
      private static final String HASH_KEY = "hash";
      private static final String SORT_KEY = "sort";
      private static final String TIMESTAMP = "timestamp";
      private static final String VALUE = "value";
      private static final String AUDIT = "audit";

      private static final String HASH_KEY_1 = "hash_1";
      private static final String SORT_KEY_1 = "sort_1";

      private static final String DATA_A = "A";
      private static final String DATA_B = "B";
      private static final String VALUE_1 = "1";
      private static final String VALUE_2 = "2";
      private static final String USER_1 = "U1";
      private static final String USER_2 = "U2";

      private static AmazonDynamoDB create() {
      AmazonDynamoDB dynamoDB = DynamoDBEmbedded.create().amazonDynamoDB();
      CreateTableRequest createTableRequest = new CreateTableRequest()
      .withTableName(TABLE_NAME)
      .withKeySchema(
      new KeySchemaElement(HASH_KEY, KeyType.HASH),
      new KeySchemaElement(SORT_KEY, KeyType.RANGE))
      .withAttributeDefinitions(
      new AttributeDefinition(HASH_KEY, ScalarAttributeType.S),
      new AttributeDefinition(SORT_KEY, ScalarAttributeType.S))
      .withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
      dynamoDB.createTable(createTableRequest);
      return dynamoDB;
      }

      private void save(final String dataName, final String value, final String audit, final Date timestamp) {
      try {
      insertNewRecord(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e) {
      try {
      insertNewData(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e2) {
      try {
      updateData(dataName, value, audit, timestamp);
      } catch (ConditionalCheckFailedException e3) {
      // Ignore: Obsolete data or same as before
      }
      }
      }
      }

      private void insertNewRecord(final String dataName, final String value, final String audit, final Date timestamp) {
      PutItemRequest putItemRequest = new PutItemRequest()
      .withTableName(TABLE_NAME)
      .addItemEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addItemEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addItemEntry(dataName, new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .addItemEntry(TIMESTAMP, new AttributeValue()
      .withS(formatISO8601Date(timestamp)))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue().withExists(false));
      ddb.putItem(putItemRequest);
      }

      private void insertNewData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue().withExists(false))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);
      }

      private void updateData(final String dataName, final String value, final String audit, final Date timestamp) {
      UpdateItemRequest updateItemRequest = new UpdateItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1))
      .addAttributeUpdatesEntry(dataName, new AttributeValueUpdate()
      .withValue(new AttributeValue()
      .addMEntry(VALUE, new AttributeValue().withN(value))
      .addMEntry(AUDIT, new AttributeValue().withS(audit)))
      .withAction(AttributeAction.PUT))
      .addAttributeUpdatesEntry(TIMESTAMP, new AttributeValueUpdate()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withAction(AttributeAction.PUT))
      .addExpectedEntry(dataName, new ExpectedAttributeValue()
      .withValue(new AttributeValue().addMEntry(VALUE, new AttributeValue().withN(value)))
      .withComparisonOperator(ComparisonOperator.NE))
      .addExpectedEntry(TIMESTAMP, new ExpectedAttributeValue()
      .withValue(new AttributeValue().withS(formatISO8601Date(timestamp)))
      .withComparisonOperator(ComparisonOperator.LT));
      ddb.updateItem(updateItemRequest);
      }

      private Map<String, AttributeValue> get() {
      GetItemRequest getItemRequest = new GetItemRequest()
      .withTableName(TABLE_NAME)
      .addKeyEntry(HASH_KEY, new AttributeValue().withS(HASH_KEY_1))
      .addKeyEntry(SORT_KEY, new AttributeValue().withS(SORT_KEY_1));
      return ddb.getItem(getItemRequest).getItem();
      }

      private AmazonDynamoDB ddb;

      @Before
      public void before() {
      ddb = create();
      }

      @Test
      public void shouldInsertNewRecord() {
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      assertThat(item.get(DATA_A).getM().get(AUDIT).getS(), is(equalTo(USER_1)));
      assertThat(item.get(DATA_B), is(nullValue()));
      }

      @Test
      public void shouldInsertNewData() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_B, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      assertThat(item.get(DATA_B).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
      }

      @Test
      public void shouldNotUpdateIfNewerExists() {
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_1, now);
      save(DATA_B, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_1)));
      }

      @Test
      public void shouldUpdateDataIfDifferent() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_A, VALUE_2, USER_1, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(now)));
      assertThat(item.get(DATA_A).getM().get(VALUE).getN(), is(equalTo(VALUE_2)));
      }

      @Test
      public void shouldNotUpdateDataIfSame() {
      Date yesterday = Date.from(Instant.now().minus(1L, ChronoUnit.DAYS));
      save(DATA_A, VALUE_1, USER_1, yesterday);
      Date now = new Date();
      save(DATA_A, VALUE_1, USER_2, now);
      Map<String, AttributeValue> item = get();
      assertThat(parseISO8601Date(item.get(TIMESTAMP).getS()), is(equalTo(yesterday)));
      }
      }






      java amazon-dynamodb






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 16 '18 at 17:37







      Javier Mr

















      asked Nov 16 '18 at 17:31









      Javier MrJavier Mr

      97312031




      97312031
























          0






          active

          oldest

          votes












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53342737%2fdynamodb-conditional-update-based-on-partial-nested-object%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53342737%2fdynamodb-conditional-update-based-on-partial-nested-object%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python