自己学習記録：Lambda で DynamoDB 連携

# 背景
もうすぐ50歳。
社内情シスで、Power Platform や C#, RPA なんかで気儘に業務改善にいそしんでいたところ
事業所間連携をしたい、という話が出てきた。

当初は組み込み開発＋ブリッジエンジニア系ってことで白羽の矢が立ったんだけど、
蓋を開けかけたら、Python + FastAPI みたいな話になって
実際に開けたら AWS for JavaScript + Android っていう・・

「え！？最初に聞いてた話と全然違いますけど？」っていう状況になった、おじいちゃんの学習記録です :laughing: 

ちなみに、Python, AWS, JavaScript, FrontEnd, Android・・・全部素人です（した？）

主担当、支援ほぼ無しで、納期はあるが、研究開発ってところが救い。

言えることはただ一つ

- **何歳になったって、学びは意志一つ**

ﾅﾝﾃﾈ :ocean: 

ちなみに、5年ほど前には福岡、大濠公園付近に住んでて、ラーメンはバリカタ派でした。
ただ、川端商店街にある、豚骨ラーメンの匂いには慣れなかった・・。その近くにあった焼きカレーの店の方が :zipper_mouth: 

閑話休題

さて、現時点で、Node.js + AWS が少し見えてきた。

ということで、今度は DynamoDB + Lambda で少し遊んでみる

ゴールイメージは、
1. DynamoDB のテーブルAに値を追加すると
1. Lambda で追加内容に応じて、別テーブルに項目追加

# まずは、DynamoDB のテーブル準備
[DynamoDB](https://ap-northeast-1.console.aws.amazon.com/dynamodbv2/home?region=ap-northeast-1#service) にて、テーブル作成

とりあえず、適当に以下で作ってみた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b8aae7db-33ea-292d-abc9-6c93dd2bebdf.png)


## 命名規則とデータ型
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html

> スカラー型 – スカラー型は 1 つの値を表すことができます。スカラー型は、数値、文字列、バイナリ、ブール、および null です。

- 特に迷うこともないところ

> ドキュメント型 – JSON ドキュメントで見られるように、入れ子の属性を持つ複雑な構造を表すことができます。ドキュメント型は、リストとマップです。

- リストが、[] で区切られた配列のような感じだけど、型混合OK。順序がある。
- マップが、{} で区切られたオブジェクトのような感じかな

> セット型 – セット型は複数のスカラー値を表すことができます。セット型は、文字セット、数値セット、およびバイナリセットです。

- リストに似てるけど、型の混合NG。順序は保持されない。

### 日付についても、数値 or 文字列で使えるよって記載有り
> 数値データ型を使用して、日付またはタイムスタンプを表すことができます。これを行うための方法の 1 つは、1970 年 1 月 1 日 00:00:00 UTC から経過した秒数であるエポックタイムを使用することです。たとえば、エポック時間 1437136300 は、2015 年 7 月 17 日の 12:31:40 PM UTC を表します。

> 文字列データ型を使用して、日付またはタイムスタンプを表すことができます。これを行う 1 つの方法は、これらの例に示すように、ISO 8601 文字列を使用することです。

## その他にわかったこと
- Partition/Sort Key は定義出来るが、その他の属性は、事前定義不要
    - [CreateTableCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/createtablecommand.html) でも、Console からでも同じ


# 次に SDK を利用して、書き込み(PutCommand at lib)
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html#usage

ここにあるコードをそのままで普通に動作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/0a8a032b-4eca-d06d-a420-37795f2d499a.png)
テーブルに対しての設定はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b9348e6f-954d-ba32-d198-5725ad600417.png)
注意点は以下

1. TableName は、値に実際の "テーブル名" を追加
1. 属性は、属性に "属性名": "値" を追加

分かるでしょ？って感じで、初めての時は何が正しいのかさっぱりなので迷いますね・・

## 未定義のリストデータを設定して PutComman で追加
テーブル定義をしてなくても、普通に突っ込めるってのが RDB しか触ったことない人間には驚き 😲
そもそも定義すら出来ない、という。Code First 的に考えればいいのかな、と。
その場合、.ts から CreateTableCommand で自動生成させたいところよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/96d91de8-7e7c-c696-1459-bd833364515d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d53449c8-9bd8-cd20-62db-eaa02856326a.png)


# Lambda で、データが挿入された際に別テーブルに反映
Labmda も使ったことなかったので、まずは反映させるだけのものを

## ラムダ作成
[関数の作成](https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/create/function) から作成

で、DynamoDB への書き込みコードは、以下にあるのをほぼそのまま利用

https://github.com/aws/aws-sdk-js-v3/blob/38b1a2882c70da815b081a378d39bb6dec06d4d2/lib/lib-dynamodb/README.md

### 詰まったところ
- Sample には Region 指定が入ってなかったので、以下のようにして追加

```javascript: region 追加
// Set the AWS Region.
export const REGION = "ap-northeast-1";

// Create an Amazon DynamoDB service client object.
export const ddbClient = new DynamoDBClient({ 
    region: REGION,
});
```

- .js で書いてたらエラーが出た。
    - .mjs にした<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d98a7135-5a84-484c-6f17-87f4b5349240.png)


## トリガーに接続
テストしたかったんだけど、実際のトリガーからくる event がさっぱりだったので、とりあえず繋げてから、と

普通に、トリガー追加で、バッチ数を 1 にして OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c0be6d6c-a5ae-99bc-9f24-0acfe9d22f12.png)

### 詰まったところ
- 追加する為には テーブル側に Stream が必要だったので設定<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b69a96e2-8330-a7b1-fa26-1f8cb825c881.png)

- 上記の際、トリガーの権限がなくて怒られた<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/4c402d98-27ac-92c9-102e-4190fe40b267.png)
    - AWSLambdaDynamoDBExecutionRole を追加

## 実際に動かして、テスト用データ取得してテスト
ログから以下のような感じで 実際の Insert/Modify/Remove のデータを取得。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b8f8364c-06d1-27d1-d7fa-757bda49c232.png)

で、テストの雛形として、DynamoDB Update とマージすれば、あとはテストが出来る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b229687e-6c85-fdaf-5d46-973807ffaee2.png)

### 詰まったところ
- いつものアクセス権
    - Lambda と DynamoDB（Stream と PutItemCommand 用）に適当に追加
- 属性指定の仕方がミスってた
    - Attribute Type を挟むとは思ってなかった・・
> AttributeType
The data type for the attribute, where:
S - the attribute is of type String
N - the attribute is of type Number
B - the attribute is of type Binary

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/APIReference/API_AttributeDefinition.html

今回、テストだったので、あるテーブルに追加されたテーブルのリストの項目数を、別テーブルに追加としてやったが、その際の項目数を数える方法が以下

```javascript: 項目数の計数
const itemCount = record.dynamodb.NewImage.Items.L.length;
```

トリガー元のテーブルはこんな感じ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/edc94653-cec0-1e7f-7d02-1e45b9593517.png)

# あとがき
Lambda が便利なんだということが分かった。
Azure Function 触りたいって思ってたけど、きっとこんな感じなんだろうなぁ・・と

とりあえず、これで分かったこと

- IAM は面倒だけど、理解しないと、アクセス権適当に付けたらやばそう。付け方も色々あるし・・
- DynamoDB
    - テーブル生成や、CRUD はなんとかなりそう
    - Secondary Index の学習が必要
- Lambda
    - テストが面白い。
    - mjs 等の理解
    - typescript からの Transcompile 方法
    - Offline 確認方法
- CloudWatch はさっぱりのまま
       
ってことで、次は [serverless](https://www.serverless.com/framework/docs/getting-started) を試行するかな

# 参考
- AWS SDK V3: 対象サービスの Clients/Libraries/Packages(middleware, util, etc.) をここから探して使う

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html

今回の DynamoDB では、以下５個あった。
パット見こんな感じ？ Stream がないと Lambda 起動は出来無さそうな感じ？
- Client: Client。Table 操作関連。Transactionも出来る？
- Stream: 24時間分の連続性が担保されたデータストリーム？ [詳細はここ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.html)
- Lib: 実際のデータ操作
- util: Data Marshal とかTool？
- DAX: Power BI の DAX ではなく、Database 高速化の為の Cache。テーブル作成時に、下に出てくるこいつ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/3f3e4711-d438-cb0c-72be-7815cc0a7e4b.png)


https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/index.html

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb-streams/index.html

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_util_dynamodb.html

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dax/index.html