Slide 1

Slide 1 text

Organize your chaotic DynamoDB (with Node.js)
 osamu.arita - LINE Fukuoka
 GWの自由研究発表会 - 11st/May/2021 


Slide 2

Slide 2 text

ABOUT ME
 ● LINE Fukuokaのエンジニア
 ○ 以前はiOSエンジニアをしていました
 ○ 今は「LINE SMART CITY GovTech プログラム」の開発サポート全般
 ● 社会人歴15年 / 社歴1年目
 ○ AWS / Firebase / Ruby on Rails / PHP(Laravel、etc..) 
 ○ iOS(swift)/ Android(Kotlin / Java)/ Flutter(Dart) 
 ● GWは、息子(現5歳)と遊ぶのが中心でした
 ● slack - #z_osamu
 
 osamu_arita
 osamu.arita


Slide 3

Slide 3 text

GWにやったこと


Slide 4

Slide 4 text

Organize your chaotic DynamoDB
 (with Node.js)


Slide 5

Slide 5 text

カオスなDynamoDBを整理する
 (with Node.js)


Slide 6

Slide 6 text

DynamoDBとは
 ● フルマネージド型NoSQLデータベース
 ○ プライマリーキー以外はスキーマレス
 ○ key-value (wide-column store) およびドキュメントデータモデルをサポート
 ● 高可用性:3つのAZ(Availability Zone)でレプリケーションを持っている


Slide 7

Slide 7 text

RDBMSとNoSQLの比較
 
 RDBMS(RDS)
 NoSQL(DynamoDB) 
 スキーマ (テーブル定義)
 スキーマあり
 プライマリーキー以外はスキーマレス 
 拡張性
 -
 高
 トランザクション
 ACID特性
 ・原子性 (Atomicity)
 ・一貫性 (Consistency)
 ・独立性 (Isolation)
 ・永続性 (Durability)
 BASE特性
 ・基本的に利用可能 (Basically Available) 
 ・厳密ではない状態遷移 (Soft state) 
 ・結果整合性 (Eventual consistency) 
 
 【備考】
 ・ConsistentRead(強い整合性のある読み込み)パラメータ あり
 ・DynamoDB Transactions API:リージョン内でACIDを保 証
 操作
 SQL
 ・Classic API
 ・PartiQL(パーティクル) - SQL互換の クエリ言語 


Slide 8

Slide 8 text

DynamoDBのテーブル要素
 Partition Key
 Sort Key
 Attribute
 Item
 Attribute
 Attribute
 Attribute
 Schema定義
 他に Secondary Index もあります 
 LSI - Sort Key以外で絞り込み。テーブル作成時に定義 
 GSI - Partition Keyを別途設定。後で追加可能。但しコスト大 


Slide 9

Slide 9 text

DynamoDBのテーブル要素
 Partition Key
 Sort Key
 Attribute
 Item
 Attribute
 Attribute
 Attribute
 Schema定義
 プログラムなどで動的に追加


Slide 10

Slide 10 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 


Slide 11

Slide 11 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 
 ファイルA:table A に「updateAt」追加 
 ファイルB:table A に「memo」追加 


Slide 12

Slide 12 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 
 エンジニアCさん参加


Slide 13

Slide 13 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 
 エンジニアCさん
 tableの構成がソースコード上でバラついて
 全然わからない!


Slide 14

Slide 14 text

Table定義を集約しよう


Slide 15

Slide 15 text

DynamoDB操作 - Node.JS
 ● AWS SDK for JavaScriptで提供されているライブラリ 
 ○ v2
 
 
 
 ○ v3
 
 
 ○ 参考
 ■ https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html
 ■ https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/welcome.html
 const {DynamoDB} = require("@aws-sdk/client-dynamodb" ); const { DynamoDBClient, ListTablesCommand }= require('@aws-sdk/client-dynamodb' ); // Commandベースでテーブル一覧取得やテーブル操作など const dbclient = new DynamoDBClient({ region: 'us-west-2' }); var AWS = require('aws-sdk'); AWS.config.update( {region: 'REGION'}); // テーブル一覧取得など var ddb = new AWS.DynamoDB({apiVersion: "2006-03-01" }); // テーブル操作 var docClient = new AWS.DynamoDB. DocumentClient({apiVersion: '2012-08-10' });

Slide 16

Slide 16 text

DynamoDB操作 - Node.JS
 ● AWS SDK for JavaScriptで提供されているライブラリ 
 ○ v2
 
 
 
 ○ v3
 
 
 ○ 参考
 ■ https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html
 ■ https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/welcome.html
 const {DynamoDB} = require("@aws-sdk/client-dynamodb" ); const { DynamoDBClient, ListTablesCommand }= require('@aws-sdk/client-dynamodb' ); // Commandベースでテーブル一覧取得やテーブル操作など const dbclient = new DynamoDBClient({ region: 'us-west-2' }); var AWS = require('aws-sdk'); AWS.config.update( {region: 'REGION'}); // テーブル一覧取得など var ddb = new AWS.DynamoDB({apiVersion: "2006-03-01" }); // テーブル操作 var docClient = new AWS.DynamoDB. DocumentClient({apiVersion: '2012-08-10' }); v3のメリット
 ・SDKがTypeScriptで記述されている 
 ・サービスごとに個別のパッケージが利用可能 
 ・新しいmiddlewareStack 
 など
 


Slide 17

Slide 17 text

DynamoDB Table定義集約 - Node.JS
 ● Amazon DynamoDB DataMapper For JavaScript 
 ○ awslabsが提供しているライブラリ 
 ○ modelを作成することでTable定義を集約できる 
 
 
 
 
 
 ○ 参考
 ■ https://github.com/awslabs/dynamodb-data-mapper-js
 ■ https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-data-mapper/
 
 @table('table_name') class MyDomainObject { @hashKey() id: string; @rangeKey({defaultProvider: () => new Date()}) createdAt: Date; @attribute() completed?: boolean; }

Slide 18

Slide 18 text

DynamoDB Table定義集約 - Node.JS
 ● Amazon DynamoDB DataMapper For JavaScript 
 ○ awslabsが提供しているライブラリ 
 ○ modelを作成することでTable定義を集約できる 
 
 
 
 
 
 ○ 参考
 ■ https://github.com/awslabs/dynamodb-data-mapper-js
 ■ https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-data-mapper/
 
 @table('table_name') class MyDomainObject { @hashKey() id: string; @rangeKey({defaultProvider: () => new Date()}) createdAt: Date; @attribute() completed?: boolean; } コードとしてはv2に対応 


Slide 19

Slide 19 text

DynamoDB Table定義集約 - Node.JS
 ● Amazon DynamoDB DataMapper For JavaScript 
 ○ awslabsが提供しているライブラリ 
 ○ modelを作成することでTable定義を集約できる 
 
 
 
 
 
 ○ 参考
 ■ https://github.com/awslabs/dynamodb-data-mapper-js
 ■ https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-data-mapper/
 
 @table('table_name') class MyDomainObject { @hashKey() id: string; @rangeKey({defaultProvider: () => new Date()}) createdAt: Date; @attribute() completed?: boolean; } dynamodb-data-mapper-annotations を利用すると
 左記のようにきれいに書けるけれど、 
 JavaScriptで記載する場合は以下の通り 
 
 class MyDomainObject {
 }
 
 Object.defineProperties(MyDomainObject.prototype, {
 [DynamoDbTable]: {
 value: 'table_name'
 },
 [DynamoDbSchema]: {
 value: {
 id: {
 type: 'String',
 keyType: 'HASH'
 },
 foo: {
 type: 'String',
 keyType: 'RANGE'
 },
 :
 },
 },
 });


Slide 20

Slide 20 text

DynamoDB Table定義集約 - Node.JS
 ● Amazon DynamoDB DataMapper For JavaScript 
 ○ awslabsが提供しているライブラリ 
 ○ modelを作成することでTable定義を集約できる 
 
 
 
 
 
 ○ 参考
 ■ https://github.com/awslabs/dynamodb-data-mapper-js
 ■ https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-data-mapper/
 
 @table('table_name') class MyDomainObject { @hashKey() id: string; @rangeKey({defaultProvider: () => new Date()}) createdAt: Date; @attribute() completed?: boolean; } dynamodb-data-mapper-annotationsを利用する場合 
 
 tsconfig.jsonで experimentalDecorators と emitDecoratorMetadata オプションを true にする必要あり
 
 tsconfig.json
 {
 "compilerOptions": {
 "experimentalDecorators ": true,
 "emitDecoratorMetadata ": true,
 }
 


Slide 21

Slide 21 text

DocumentClient(v2)とDataMapperの比較 (1)
 
 DocumentClient(v2) 
 DataMapper
 scan
 scan(params, callback) ⇒ AWS.Request 
 scan( 
 valueConstructor: ZeroArgumentsConstructor, 
 options?: ScanOptions|ParallelScanWorkerOptions 
 ): ScanIterator;
 get
 get(params, callback) ⇒ AWS.Request 
 get( 
 item: T,
 options?: GetOptions 
 ): Promise;
 put
 put(params, callback) ⇒ AWS.Request 
 put( 
 item: T,
 options?: PutOptions 
 ): Promise;
 一通りのメソッドは用意されている。scanは戻り値の型がPromiseではないので注意 


Slide 22

Slide 22 text

DocumentClient(v2)とDataMapperの比較 (2)
 
 DocumentClient(v2) 
 DataMapper
 update
 update(params, callback) ⇒ AWS.Request
 update( 
 item: T,
 options?: UpdateOptions 
 ): Promise;
 delete
 delete(params, callback) ⇒ AWS.Request
 delete( 
 item: T,
 options?: DeleteOptions 
 ): Promise;
 ● 参考
 ○ https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html
 ○ https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-data-mapper/
 ○ https://github.com/awslabs/dynamodb-data-mapper-js/blob/master/packages/dynamodb-data-mapper/src/DataMapper.ts
 一通りのメソッドは用意されている 


Slide 23

Slide 23 text

試してみよう


Slide 24

Slide 24 text

試してみた構成
 エンジニアAさん
 ・言語:TypeScript(※1) 
 ・DynamoDB:create-table / put-item 
 ・AWS Lambda:create-function / delete-function / invoke 
 (※1)dynamodb-data-mapperのサンプルがTypeScriptベース 
 localstack
 DynamoDB
 AWS Lambda 
 Node.js
 テーブル:
 SurveyResults 
 
 ● 参考
 ○ https://github.com/localstack/localstack
 ○ https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.html
 ・AWS提供のNoSQL Workbenchで実際のデータ確認 


Slide 25

Slide 25 text

試してみた構成
 エンジニアAさん
 ・言語:TypeScript(※1) 
 ・DynamoDB:create-table / put-item 
 ・AWS Lambda:create-function / delete-function / invoke 
 (※1)dynamodb-data-mapperのサンプルがTypeScriptベース 
 localstack
 DynamoDB
 AWS Lambda 
 Node.js
 テーブル:
 SurveyResults 
 
 ● 参考
 ○ https://github.com/localstack/localstack
 ○ https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.html
 ・AWS提供のNoSQL Workbenchで実際のデータ確認 
 ・サービス共通で http://localhost:4566/ にてアクセス可能
 ・localstack内でアクセスする場合、 http://${process.env.LOCALSTACK_HOSTNAME}:4566 
 とLOCALSTACK_HOSTNAMEを利用することでアクセス可能 


Slide 26

Slide 26 text

今回作成したリポジトリ
 https://github.com/noeloasis/localstack-dynamodb
 
 必要に応じて「-g」を「-D」にしてください 
 事前準備。記載されているコマンドを実行します
 localstackに接続するためのAWS profileを作成します
 Access Key, Secret Access Keyの値は何でも良いですが 
 コード内で指定しているため、このまま入力します 


Slide 27

Slide 27 text

今回作成したリポジトリ
 Dockerは事前にインストールしてください
 healthイメージ
 localstackを別のディレクトリにcloneして起動(up)します
 localstackを停止(down)する場合は次のコマンドを実行します


Slide 28

Slide 28 text

今回作成したリポジトリ
 https://github.com/noeloasis/localstack-dynamodb
 
 setup →「SurveyResults」テーブル作成+1件item登録
 update_lambda_01 → DocumentClient(v2)サンプルのLambda作成
 update_lambda_02 → DataMapperサンプルのLambda作成
 run_lambda_01 → DocumentClient(v2)サンプルのLambda実行
 run_lambda_02 → DataMapperサンプルのLambda実行
 list_lambda → 登録されているLambdaのリストを表示


Slide 29

Slide 29 text

今回作成したリポジトリ
 https://github.com/noeloasis/localstack-dynamodb
 
 記載されている通りに設定してください


Slide 30

Slide 30 text

今回作成したリポジトリ
 https://github.com/noeloasis/localstack-dynamodb
 
 
 NoSQL Workbenchのイメージ 
 「./bin/setup」を実行した直後です 
 「SurveyResults」テーブル作成+1件 item登録されています 


Slide 31

Slide 31 text

demo


Slide 32

Slide 32 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 
 エンジニアCさん
 tableの構成がソースコード上でバラついて
 全然わからない!


Slide 33

Slide 33 text

とあるプロジェクトの構成
 エンジニアAさん
 リポジトリ
 エンジニアBさん
 GitHub
 commit & push
 commit & push
 deploy (AWS CloudFormation, AWS SAM) 
 
 pull
 pull
 AWS(Serverless構成)
 DynamoDB
 AWS Lambda 
 API Gawatey
 Node.js
 table A
 table B
 ※フロントエンドなど細かい部分は省略 
 エンジニアCさん
 tableの構成がソースコード上で
 わかる(わかりそう)!


Slide 34

Slide 34 text

まとめ
 ● カオスなDynamoDB
 ○ 複数のエンジニアが開発を行い、table情報がソースコード上でばらついている状態 
 ● DataMapperを利用する事で、モデルとして整理できそう
 ○ ただし・・
 ■ scanの戻り値の型がScanIteratorでPromiseと異なるので注意 
 ■ AWS SDK for JavaScript (v3) を利用したい場合は、別の方法を検討 
 ● DynamoDBを試したい場合、localstack+NoSQL Workbenchは便利!


Slide 35

Slide 35 text

Thank You !
 ご清聴ありがとうございました!