Lambda(Python3.6)でDynamoDBに登録された項目が日付型であるかチェックしてみる

2017.10.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも!大阪オフィスの西村祐二です。

DynamoDBで提供されている属性の型は大きく分けて スカラー型、ドキュメント型、セット型となっています。

DynamoDBの命名ルールおよびデータ型

そのため、下記画像のように日付と時刻を登録するときは文字列データ型(String型)を使用するのがほとんどだと思います。

2017-10-20_20_01_56

ただ、こちらが想定するフォーマット以外でも登録することができてしまい、 登録された時刻をみて、ある処理を実行するときなど 処理が失敗してしまう可能性があります。

今回はLambdaを使って登録されている項目のフォーマットが正しいかチェックしてみたいと思います。

DynamoDBのテーブル作成

今回はCloudFormationを使ってDynamoDBのテーブルを作成します。

テンプレートファイルを作成します。 今回作成するテーブルはプライマリーキー「Date」、ソートキー「Time」とし、 属性のデータ型を文字列データの「S」として設定しています。

$ vi dynamodb.yml

dynamodb.yml

---
AWSTemplateFormatVersion: "2010-09-09"

Resources:
  myDynamoDBTable:
    Type: "AWS::DynamoDB::Table"
    Properties:
      TableName: "dynamo-test"
      AttributeDefinitions:
        - AttributeName: Date
          AttributeType: S
        - AttributeName: Time
          AttributeType: S
      KeySchema:
        - AttributeName: Date
          KeyType: HASH
        - AttributeName: Time
          KeyType: RANGE
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

下記コマンドにてテーブルを作成します。

$ aws cloudformation validate-template --template-body file://dynamodb.yml
$ aws cloudformation create-stack dynamodb-test --template-body file://dynamodb.yml

成功したら下記画像のように作成されているはずです。

2017-10-20_21_56_52

Lambda関数の作成

AWS Management Consoleにログインして、AWS Lambda Dashboardを開きます。 Lambda関数一覧の画面で、[関数の作成]ボタンをクリックします。 [一から作成]ボタンをクリックします。 名前を[dynamodb-check]とし、 ロールにはDynamoDBのテーブルをスキャンするので "dynamodb:Scan"を付与しておいてください。 [関数の作成]ボタンをクリックします。

移動した画面で、ランタイムのドロップダウンリストからPython 3.6を選択します。 下記、プログラムをコピペし、保存ボタンをクリックします。

import boto3
import logging
from datetime import datetime

# dynamodb
DYNAMO_TABLE_NAME = 'dynamodb-test'
dynamodb = boto3.resource('dynamodb')
table    = dynamodb.Table(DYNAMO_TABLE_NAME)

def format_check(data):
    try:
        for i in range(len(data)):
            dynamo_datetime = str(data[i]['Date'])+ " " + str(data[i]['Time'])
            ## 日時フォーマットに変換 (ex:2017-10-19 01:01)
            get_datetime = datetime.strptime(dynamo_datetime, '%Y-%m-%d %H:%M')
            print(get_datetime)
        print('ok')
    except Exception as e:
        logger.exception("{}".format(e))
        return "ERROR End"

def handler(event, context):
    try:
        response = table.scan()
        data = response['Items']
        format_check(data)
    except Exception as e:
        logger.exception("{}".format(e))
        return "ERROR End"

簡単に解説します。 ポイントは15行目です。

get_datetime = datetime.strptime(dynamo_datetime, '%Y-%m-%d %H:%M')

pythonのdatetime.strptimeはかなり便利で、 日付や時刻に対応する書式文字列から datetime オブジェクトに変換してくれます。

また、strptimeの第二引数は第一引数のフォーマットを渡すため、 これにマッチしないとエラーとなります。 ここでエラーになるということは、つまり、想定しないフォーマットで入力されていることになります。

今回の場合は Date:2017-10-19 のような日付 Time:01:01 のような時刻が 入力されている想定です。

また、入力してほしいフォーマットが Date:2017/10/19 のような日付の場合は 第二引数を%Y/%m/%dのように対応する形に変更すれば、OKです。

get_datetime = datetime.strptime(dynamo_datetime, '%Y/%m/%d %H:%M')

動作確認

DynamoDBにいろいろなデータをいれて、 動作を確認してみたいと思います。

正しいフォーマットでいれてみる

[項目の作成]をクリックして、 Date:2017-10-20 Time:20:20 を登録してみました。

2017-10-20 22.54.13

作成したLambda関数を実行させてみると 下記ログが出力され問題なく、変換できていることがわかります。

2017-10-20_23_01_43

時刻を一桁のままでいれてみる

[項目の作成]をクリックして、 Date:2017-10-20 Time:1:1 を登録してみました。

2017-10-20 23.08.28

作成したLambda関数を実行させてみると 下記ログが出力され問題なく、変換できていることがわかります。

2017-10-20_23_08_44

全角を入れてみる

[項目の作成]をクリックして、 Date:2017−10−20 Time:20:20 を登録してみました。

2017-10-20 23.15.50

作成したLambda関数を実行させてみると 下記ログが出力され想定どおり、エラー出力ができていることがわかります。

2017-10-20_23_14_08

ありえない日程をいれてみる

[項目の作成]をクリックして、 Date:2017-15-10 Time:20:20 を登録してみました。

2017-10-20 23.19.37

作成したLambda関数を実行させてみると 下記ログが出力され想定どおり、エラー出力ができていることがわかります。

2017-10-20_23_20_04

ありえない時刻をいれてみる

[項目の作成]をクリックして、 Date:2017-10-20 Time:25:20 を登録してみました。

2017-10-20 23.28.52

作成したLambda関数を実行させてみると 下記ログが出力され想定どおり、エラー出力ができていることがわかります。

2017-10-20_23_29_02

追加で、 Date:2017-10-20 Time:20:80 を登録してみました。

2017-10-20 23.21.01

作成したLambda関数を実行させてみると 下記ログが出力され 今回はなぜかunconverted dataというようなエラーが出力されました。

2017-10-20_23_22_31

さいごに

いかがだったでしょうか。 Lambdaをつかって DynamoDBに登録された項目が日付型であるかチェックしてみました。 あとは、Lambdaで定期的に確認しエラーが出力されれば ユーザにメールを送信すればとりあえずは良いかと思います。 もっといいやり方があれば教えてください。

誰かのためになれば幸いです。