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;
}
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
add a comment |
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
add a comment |
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
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
java amazon-dynamodb
edited Nov 16 '18 at 17:37
Javier Mr
asked Nov 16 '18 at 17:31
Javier MrJavier Mr
97312031
97312031
add a comment |
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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