How do you "upsert" a property to a DynamoDB row. E.g. SET address.state = "MA"
for some item, when address
does not yet exist?
I feel like I'm having a chicken-and-egg problem because DynamoDB doesn't let you define a sloppy schema in advance.
If address
DID already exist on that item, of type M
(for Map), the internet tells me I could issue an UpdateExpression like:
SET #address.#state = :value
with #address
, #state
, and :value
appropriately mapped to address
, state
, and MA
, respectively.
But if the address
property does not already exist, this gives an error:
''' ValidationException: The document path provided in the update expression is invalid for update '''
So.. it appears I either need to:
address.state
(e.g., SET address = {}; SET address.state = 'MA'
in a single command)or
SET address = {};
on failure, and then try it again.If the latter.... how do I set a blank map?!?
Ugh.. I like Dynamo, but unless I'm missing something obvious this is a bit crazy..
You can do it with two round trips, the first conditionally sets an empty map for address
if it doesn't already exist, and the second sets the state
:
db.update({ UpdateExpression: 'SET #a = :value', ConditionExpression: 'attribute_not_exists(#a)', ExpressionAttributeValues: { ":value": {}, }, ExpressionAttributeNames: { '#a': 'address' } }, ...);
Then:
db.update({ UpdateExpression: 'SET #a.#b = :v', ExpressionAttributeNames: { '#a': 'address', '#b': 'state' }, ExpressionAttributeValues: { ':v': 'whatever' } }, ...);
You cannot set nested attributes if the parent document does not exist. Since address
does not exist you cannot set the attribute province
inside it. You can achieve your goal if you set address
to an empty map when you create the item. Then, you can use the following parameters to condition an update on an attribute address.province
not existing yet.
var params = { TableName: 'Image', Key: { Id: 'dynamodb.png' }, UpdateExpression: 'SET address.province = :ma', ConditionExpression: 'attribute_not_exists(address.province)', ExpressionAttributeValues: { ':ma': 'MA' }, ReturnValues: 'ALL_NEW' }; docClient.update(params, function(err, data) { if (err) ppJson(err); // an error occurred else ppJson(data); // successful response });
By the way, I had to replace state with province as state is a reserved word.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With