📑
S3をトリガーにしてDynamo DBにデータを格納するLambdaを作くってみた(テストも)
はじめに
この記事では、AWS Lambdaを使用して、S3から取得したTSV(Tab Separated Values)ファイルの内容をDynamoDBに保存する方法を解説します。
この実装を行うことで、S3にアップロードされたTSVファイルを自動的にDynamoDBに登録するシステムを構築できます。
前提条件
AWSアカウントを持っていること。
AWS CLIがインストールされ、AWSアカウントにアクセスできること。
Node.jsがインストールされていること。
LambdaStackの内容
あくまでLambdaだけ共有します。
Lambdaの実装
import {S3Event} from 'aws-lambda'
import AWS from 'aws-sdk'
import csvParser from 'csv-parser'
export const handler = async (event:S3Event) => {
const s3 = new AWS.S#()
const dynamoDB = new AWS.DynamoDB.DocumentClient()
const tableName = 'id_catalog_develop'
try{
const bucketName = event.Records[0].s3.bucket.name
const objectKey = event.Records[0].s3.object.key
if(!objectKey.includes('.tsv')){
//このLambdaはtsvの拡張子しか受け入れないような仕様にしているため
throw new Error('objectKey is not a .tsv file')
}
const s3stream = s3.getObject({Bucket:bucketName,Key:objectKey})
const tsvParser = s3stream.pipe(csvParser({separator:'\t'}))
const sequenceParam = {
TableName:'sequence'
Key:{
//DynamoDBのパーティションキー↓
seq_name:'tableName'
}
}
for await(const row of tsvParser){
//↓擬似的なauto incrementを作成するためのテーブル
const data = await dynamoDB.get(sequenceParam).promise()
let incrementNumber = Number(data.Item?.current_number)
if(isNaN(incrementNumber)){
//デフォルトの値を0とする
incrementNumber = 0
}
const param = {
TableName:tableName,
Key:{
sid:incrementNumber.toString()
}
}
const item = {
...row,
sid:incrementNumber.toString()
}
await dynamoDB.put({ TableName:tableName ,Item: item }).promise()
}
incrementNumber++
const sequenceItem = {
seq_name:tableName,
current_number:incrementNumber
}
await dyanmoDB.put({ TableName:sequence ,Item: sequenceItem })
}catch(error){
return error
}
}
Lambdaのテスト
import {S3Event} from `aws-lambda`
import * as lambda from `テストをしたいファイルのPATH`
import AWSMock from `aws-sdk-mock`
const bucketName = `bucket-name`
const objectKey = `object-key.tsv`
const dummyData = Column1\tColumn2\tColumn3
Data1\tValue1\t100
Data2\tValue2\t200
Data3\tValue3\t300
Data4\tValue4\t400
Data5\tValue5\t500
describe(
it(`正常系`,async() => {
//S3のgetObjectを使用されたときにはこのMockを返却しますよって感じ
AWSMock.mock(`s3`,`getObject`,Buffer.from(dummyData))
const putMock = jest.fn().mockReturnValue((promise:() => Promise.resolve))
AWSMock.mock(`DynamoDB.DocumentClient`,`put`,putMock)
//このeventは調べたらすぐ出てきます
const res = await lambda.handler(event)
expext(res).toBe(undefind)
expect(putMock.mock.calls[0][0].TableName).toBe(`id_catalog_develop`)
expect(putMock.mock.calls[0][0].Item).toEqual({
})
})
)
あとで書きます
Discussion