Lambda関数(C#)でDynamoDBにUpdateItem(データ更新)する方法


Lambda 関数(C#)で DynamoDB にアクセスして UpdateItem (データ更新)する方法をメモしておきます。

まず、DynamoDBのItemIdというテーブルを以下のように作成します。パーティションキーはidで、_versionはキーではない属性になります。

項目は以下のように2件登録されていて、CategoryIdの項目を更新対象とします。

また、_version 属性が 0 の場合のみ更新するように条件を付与します。

f:id:fnyablog:20181112172314p:plain:w320

Lambda 関数(C#)で UpdateItem するには、以下のように記述します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace AWSLambda1
{
    public class Function
    {
        public async Task FunctionHandler(object input, ILambdaContext context)
        {
            AmazonDynamoDBClient client = new AmazonDynamoDBClient();
            string tableName = "ItemId";

            try
            {
                var request = new UpdateItemRequest
                {
                    TableName = tableName,
                    Key = new Dictionary<string, AttributeValue>()
                    {
                        {
                            "id", new AttributeValue()
                            {
                                S = "CategoryId"
                            }
                        }
                    },
                    ExpressionAttributeNames = new Dictionary<string, string>()
                    {
                        { "#v", "_version" }
                    },
                    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
                    {
                        { ":version", new AttributeValue()
                            {
                                N = "1"
                            }
                        },
                        { ":default_version", new AttributeValue()
                            {
                                N = "0"
                            }
                        }
                    },

                    // Update式
                    UpdateExpression = "SET #v = :version",

                    // 条件式
                    ConditionExpression = "#v = :default_version",

                    ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.

                };

                var response = await client.UpdateItemAsync(request);

                var attributeList = response.Attributes;
                PrintItem(attributeList);

                Console.WriteLine("Task completed.");


            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            
        }

        private void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            Console.WriteLine("************************************************");

            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }

            Console.WriteLine("************************************************");
        }

    }
}

実行結果のログは以下のようになり、更新後の値が取得できていることが分かります。

f:id:fnyablog:20181112172731p:plain:w640

また、DynamoDB の項目を確認すると、CategoryId の _version が 1 になっており、正しく更新されていることが分かります。

f:id:fnyablog:20181112172839p:plain:w320

この Lambda 関数を2回実行すると、2回目は該当する項目がないため、以下のような例外がログに出力されました。

f:id:fnyablog:20181112172958p:plain:w640

処理的には、例外ではなく0件で処理をして欲しいところですが、NoSQL はこういうものなのでしょうか。

なお、参考サイトは以下のものになります。

docs.aws.amazon.com