DynamoDBテーブルからStartとEndの期間を指定して任意デバイスのデータを取得する

DynamoDBテーブルに保存してあるデータに対して、Start/Endの期間を指定してデータ取得してみました。
2020.10.01

DynamoDBに保存しているデータから、指定した期間のデータを取得したいことがあります。

  • 指定した期間において、ドアが開いた回数が知りたい
  • 指定した期間のデータでグラフを表示したい

そこで本記事では、DynamoDBに溜まっている「ドアセンサーがAWSに送信したOpenイベント」があると仮定して、任意期間で取得してみました。

環境

項目 バージョン
Python 3.7

データの準備をする

DynamoDBテーブルを作成する

  • Hashキー:ドアデバイスのID
  • Rangeキー:Openした時刻(ミリ秒)
aws dynamodb create-table \
    --table-name door-usage-table \
    --attribute-definitions \
        AttributeName=doorId,AttributeType=S \
        AttributeName=timestamp,AttributeType=N \
    --key-schema \
        AttributeName=doorId,KeyType=HASH \
        AttributeName=timestamp,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST

DynamoDBテーブルにサンプルデータを格納する

次のPythonスクリプトを実行します。データ数が多いと確認しにくいため、「1デバイスあたり10回」のイベントを3デバイス追加します。 なお、年月日時は固定とし、分秒をランダムにしています。

putter.py

import boto3
import random
from datetime import datetime

TABLE_NAME = 'door-usage-table'

dynamodb = boto3.resource('dynamodb')

def put():
    table = dynamodb.Table(TABLE_NAME)
    for device_number in range(3):
        put_open_event_data(device_number, table)

def put_open_event_data(device_number, table):
    with table.batch_writer() as writer:
        for i in range(10):
            timestamp = get_timestamp()
            writer.put_item(
                Item={
                    'doorId': f'door-{device_number}',
                    'timestamp': int(timestamp.timestamp()) * 1000,
                    'iso8601': timestamp.isoformat()
                }
            )

def get_timestamp():
    rand_minute = int(random.uniform(0, 59))
    rand_second = int(random.uniform(0, 59))
    return datetime(2020, 9, 10, 13, rand_minute, rand_second)

if __name__ == "__main__":
    put()

実行するとデータが溜まります。

python putter.py

デバイスID:0のデータ

デバイスID:1のデータ

デバイスID:2のデータ

期間指定してDynamoDBテーブルからデータ取得する

データの準備ができたため、期間指定してDynamoDBテーブルからデータを取得します。 ここでは下記時刻を指定しました。

unixtime 時刻
開始時刻 1599711000000 2020-09-10T13:10:00
終了時刻 1599711620000 2020-09-10T13:20:20

KeyConditionExpressionbetweenで開始時刻と終了時刻を指定しています。

import json
import boto3
from boto3.dynamodb.conditions import Key

TABLE_NAME = 'door-usage-table'
START_TIMESTAMP = 1599711000000     # 2020-09-10T13:10:00
END_TIMESTAMP = 1599711620000       # 2020-09-10T13:20:20

dynamodb = boto3.resource('dynamodb')

def get():
    table = dynamodb.Table(TABLE_NAME)
    for device_number in range(3):
        data = get_usage(f'door-{device_number}', table)
        print(data)

def get_usage(doorId, table):
    option = {
        'KeyConditionExpression':
            Key('doorId').eq(doorId) & \
            Key('timestamp').between(START_TIMESTAMP, END_TIMESTAMP)
    }
    resp = table.query(**option)
    return resp.get('Items', [])

if __name__ == "__main__":
    get()

スクリプトを実行する

python getter.py

実行結果

指定した範囲のデータのみを取得できました!

取得したデータ(デバイスID:0)

[
    {
        'iso8601': '2020-09-10T13:10:28',
        'doorId': 'door-0',
        'timestamp': Decimal('1599711028000')
    },
    {
        'iso8601': '2020-09-10T13:12:05',
        'doorId': 'door-0',
        'timestamp': Decimal('1599711125000')
    },
    {
        'iso8601': '2020-09-10T13:18:11',
        'doorId': 'door-0',
        'timestamp': Decimal('1599711491000')
    }
]

取得したデータ(デバイスID:1)

[
    {
        'iso8601':
        '2020-09-10T13:14:31',
        'doorId': 'door-1',
        'timestamp': Decimal('1599711271000')
    }
]

取得したデータ(デバイスID:2)

[] # データなし

さいごに

DynamoDBテーブルから期間を指定してデータ取得してみました。 たとえば、デバイスから来たデータを溜めておき、任意期間のデータを取得したいケースなので活用できると思います。 保存期間が決まっているのであれば、DynamoDBのTTL機能を使って自動削除もできますね。

参考