Reputation: 4552
I have something like this:
{
Records:{}
}
and I just want to add data inside records like this:
{
Id: 123,
Records:{
10001: { event : "item1" }
}
}
My 1st attempt:
var params = {
TableName : "Records",
Key : { Id : 123 },
UpdateExpression: 'set Record.#k1.event = :v1',
ExpressionAttributeNames: { '#k1' : 10001},
ExpressionAttributeValues: { ':v1' : 'item1' }
};
Because Record.10001 doesn't exist, it give me error:
The document path provided in the update expression is invalid for update
"ADD" only support NUMBER and SET type so its not suitable in my case.
My 2nd attempt (trying to create a empty map 1st):
var params = {
TableName : "Records",
Key : { Id : 123 },
UpdateExpression: 'set Record.#k1 = {}',
ExpressionAttributeNames: { '#k1' : 10001},
};
It fails as my syntax is probably incorrect and I cannot find how to create a empty map to an attribute.
So my question is how do I add structured object as a map or empty map to an existing item like the example above?
I can easily modifying the data from the amazon DynamoDB data management page so at least I know there exist a way to do it. I just need to know how.
Thanks
Upvotes: 16
Views: 20604
Reputation: 1
var params = {
TableName : "Records",
Key : { Id : 123 },
UpdateExpression: 'set #Records = :obj',
ExpressionAttributeNames: { '#Records' : 'Records'},
ExpressionAttributeValues: { ':obj' : {'10001': { 'event' : 'item1' }}}
};
Upvotes: 0
Reputation: 1361
This can be done in c# as follows.
If you have the following json:
"invoice":{ "M":{ ":number":{ "S":"XPN1052" }":date":{ "S":"02-17-2022" } } }
You can use the following code to insert an invoice record:
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":invoice", new AttributeValue { M = new Dictionary<string, AttributeValue>{
{":date", new AttributeValue { S = invoice.TxnDate.ToString("MM-dd-yyyy") }},
{":number", new AttributeValue{ S = invoice.DocNumber } } }
} }},
UpdateExpression = "SET invoice = :invoice",
Upvotes: 0
Reputation: 2099
In order to insert/update Dynamodb items dynamically based on a given dictionary with various keys (eventually columns in Dynamodb) we can construct query string as shown below:
# given dictionary with needs to be dumped into dynamodb
dict_to_insert = {'column1':'value1',
'column2.subdocument1':{'subkey1':'subvalue1',
'subkey2':'subvalue2'}...}...
# placeholder variables
# Using upsert for insert/update mllog records on dynamodb
query = "SET"
values_dict = {}
names_dict = {}
i = 0
# iterating over given dictionary and construct the query
for key, value in dict_to_insert.items():
# if item key column provide in the given dictionary
# then it should be skipped
if key == 'ITEM_KEY_NAME':
i += 1
continue
# None values causing error on update_item
# So, better to ignore them as well
if value is not None:
# if_not_exists method prevents overwriting existing
# values on columns
query += " " + "#k_" + str(i) + " = if_not_exists(#k_" + str(i) + \
", :v_" + str(i)+")"
if key != list(dict_to_insert.keys())[-1]: # if not the last attribute add ,
query += ","
# Defining dynamodb columns and their corresponding values
values_dict["#k_" + str(i)] = key
names_dict[":v_" + str(i)] = value
i += 1
Once we construct the query string as shown above, then we can confidently run our update_item method on Dynamodb:
# table obj here is boto3 dynamodb resource instance
table.update_item(
TableName='DYNAMODB_TABLENAME',
Key={'ITEM_KEY_NAME': 'ANY_VALUE_AS_KEY'},
UpdateExpression=query.strip(),
ExpressionAttributeNames=names_dict,
ExpressionAttributeValues=values_dict)
Upvotes: -2
Reputation: 2298
one of the possible resolution to get rid of such problem: you have to have an empty object created and exist in DB in advance.
for instance,
during generation of your object (original creation in DB):
field: { }
to update this field use:
TableName: ....,
Key: {
.....
},
UpdateExpression: 'set field.#mapKey = :v',
ExpressionAttributeNames: {
'#mapKey': myName
},
ExpressionAttributeValues: {
':v': myValue
}
Upvotes: 2
Reputation: 1269
I found a workaround for the error we get.
try:
table.update_item(
Key = {'Id' : id},
UpdateExpression = 'SET Records.#key1.#key2 = :value1',
ExpressionAttributeNames = {'#key1': '10001', '#key2' : 'event'},
ExpressionAttributeValues = {':value1': 'singing'}
)
except:
table.update_item(
Key = {'Id' : id},
UpdateExpression = 'SET Records = :value1',
ExpressionAttributeValues = {':value1': {'10001': {'event' : 'dance'}}}
)
When we try to update for the first time we get "The document path provided in the update expression is invalid for update" error. An exception will be thrown since there will be no nested JSON.
Thereafter, any updates say for example Record.10002 will not throw exception. Update function in the try block will be executed.
Please comment on this if this is the correct way of handling this kind of scenario.
Upvotes: 2
Reputation: 4552
I somehow successfully done it this way:
var params = {
TableName: "Records",
Key: { Id: 123 },
UpdateExpression: 'set Records.#k1 = :v1',
ExpressionAttributeNames: {'#k1': '10001',},
ExpressionAttributeValues: {':v1': { event: 'Yay~' } }
};
optionally you could use
UpdateExpression: 'set Records.#k1 = if_not_exists( Records.#k1, :v1)',
to avoid overwriting existing records.
Upvotes: 14