2

I have a scenario where I want to create an item if it doesn't exist, or update an item - incrementing a total, if it already exists.

I was running into problems splitting the two operations, so I am now trying to do both using UpdateItem in a single command.

I've tried 3 different approaches none work, and they have different errors listed below, the problem it seems is creating the map and trying to update it in a single command - what should my update params look like?

Attempt one:

 {
    TableName: TableName,
    Key: {
        'key': key
    },
    UpdateExpression: `
        ADD #total :change
        ,   mapname.#type.#total :one
    `,
    ExpressionAttributeValues: {
        ':change': change,
        ':one': 1
    },
    ExpressionAttributeNames: {
        '#type': 'dynamicstring',
        '#total': 'total'
    }
};

With an error of: ValidationException: The document path provided in the update expression is invalid for update

Attempt two:

{
    TableName: TableName,
    Key: {
        "key": key
    },
    UpdateExpression: `
        SET custommap = if_not_exists(custommap, :emptyMap)
        SET #total = #total + :change, 
        custommap.#type.#total = custommap.#type.#total + :one
    `,
    ExpressionAttributeValues: {
        ':change': change,
        ':one': 1,
        ':emptyMap': {
            'M': {
                'dynamicstring': {
                    'M': {
                        'total': {
                            'N': 0
                        }
                    }
                }
            }
        }
    },
    ExpressionAttributeNames: {
        '#type': 'dynamicstring',
        '#total': 'total'
    }
}

With an error of: ValidationException: Invalid UpdateExpression: The "SET" section can only be used once in an update expression;

So when I use UpdateItem to create or update (increment) a map within an Item, what syntax is correct?

Thanks

shenku
  • 11,969
  • 12
  • 64
  • 118

1 Answers1

0

SET will only stop you overwriting an attribute, not an item.

They way to achieve this is:

  1. Use GetItem with your key to see if the item already exists
  2. If the item exists, then do an UpdateItem and increment the counter
  3. If the item does not exist, then use PutItem
F_SO_K
  • 13,640
  • 5
  • 54
  • 83
  • 1
    I previously tried this approach but found that after the initial CreateItem, further GetItems weren't returning the new item until much later, which is why I was looking for an approach where I could do both at once. – shenku Jan 31 '18 at 00:07
  • That suggests to me your table was under provisioned and your requests were being throttled. Did you try increasing WCUs and RCUs? – F_SO_K Jan 31 '18 at 08:23
  • If you read [this answer about throttling](https://stackoverflow.com/a/48025081/4985580), hopefully that will help. – F_SO_K Jan 31 '18 at 08:28
  • If you are writing a large item with only 1 WCU and 1 RCU provisioned, [this answer](https://stackoverflow.com/questions/48287364/aws-dynamo-db-throughput/48290423#48290423) may be relevant. – F_SO_K Jan 31 '18 at 08:29
  • 1
    @Stu what about race condition? If there would be too many updates per second it'll overwrite the updated value or throw the exception with optimistic lock. – Orest Jan 05 '19 at 02:43