rustamazon-dynamodbaws-sdk-rust

How to append elements to a list in DynamoDB using Rust


I'm struggling using list_append programmatically in Rust.

I have a table called Humidities:

{
 "id": 177,
 "Measurements": [
  49
 ]
}

and I want to add elements. For example:

{
 "id": 177,
 "Measurements": [
  49,
  53
 ]
}

This is a working solution for python, which I've found here :

table = get_dynamodb_resource().Table("table_name")
result = table.update_item(
    Key={
        'hash_key': hash_key,
        'range_key': range_key
    },
    UpdateExpression="SET some_attr = list_append(some_attr, :i)",
    ExpressionAttributeValues={
        ':i': [some_value],
    },
    ReturnValues="UPDATED_NEW"
)
if result['ResponseMetadata']['HTTPStatusCode'] == 200 and 'Attributes' in result:
    return result['Attributes']['some_attr']

Based on the python solution I've tried this:

#[tokio::main]
async fn main() -> Result<(), Error> {
    let Opt { base } = Opt::from_args();
    let shared_config = make_config(base).await?;
    let client = Client::new(&shared_config);
    client
        .update_item()
        .table_name("Humidities")
        .key("id", AttributeValue::N(177.to_string()))
        .update_expression("SET i = list_append(Measurements, :i)")
        .expression_attribute_values("i", AttributeValue::N(53.to_string()))
        .send()
        .await?;
    Ok(())
}

However, the result is:

Error: Unhandled(Error { code: Some("ValidationException"), message: Some("ExpressionAttributeValues contains invalid key: Syntax error; key: \"i\""), request_id: Some("05RSFGFJEEDPO7850LI2T91RGRVV4KQNSO5AEMVJF66Q9ASUAAJG"), extras: {} })

What am I doing wrong?

The examples only demonstrate how to add a single item: https://github.com/awslabs/aws-sdk-rust/blob/main/examples/dynamodb/src/bin/add-item.rs

I've also tried this:

#[tokio::main]
async fn main() -> Result<(), Error> {
    let Opt { base } = Opt::from_args();
    let shared_config = make_config(base).await?;
    let client = Client::new(&shared_config);
    client
        .update_item()
        .table_name("Humidities")
        .key("id", AttributeValue::N(177.to_string()))
        .update_expression("set #Measurements = list_append(#Measurements, :value)")
        .expression_attribute_names("#Measurements", "Measurements")
        .expression_attribute_values("value", AttributeValue::N(53.to_string()))
        .return_values(aws_sdk_dynamodb::model::ReturnValue::AllNew)
        .send()
        .await?;
    Ok(())
}

with a look at: Append a new object to a JSON Array in DynamoDB using NodeJS

Same result, value is unknown:

Error: Unhandled(Error { code: Some("ValidationException"), message: Some("ExpressionAttributeValues contains invalid key: Syntax error; key: \"value\""), request_id: Some("1A8VEOEVSB7LMAB47H12N7IKC7VV4KQNSO5AEMVJF66Q9ASUAAJG"), extras: {} }) 

Solution

  • I've found a solution. There have been two problems:

    Running example:

    async fn main() -> Result<(), Error> {
        let Opt { base } = Opt::from_args();
        let shared_config = make_config(base).await?;
        let client = Client::new(&shared_config);
        client
            .update_item()
            .table_name("Humidities")
            .key("id", AttributeValue::N(177.to_string()))
            .update_expression("set #Measurements = list_append(#Measurements, :value)")
            .expression_attribute_names("#Measurements", "Measurements")
            .expression_attribute_values(
                ":value", // changed from "value" to ":value"
                AttributeValue::L(vec![AttributeValue::N(53.to_string())]), // use a vector of numbers instead of a number
            )
            .return_values(aws_sdk_dynamodb::model::ReturnValue::AllNew)
            .send()
            .await?;
        Ok(())
    }