DynamoDBのデータ型を取り除く(Python3版)


はじめに

DynamoDBから値を取得するときに、batch_get_itemの戻り値やDynamoDB Streamのイベントに格納されるデータの形式が、次のようにデータ型を含んだ形になっていて、そのままでは扱いづらくなっています。

{
    'userId': {
        'N': '12345'
    },
    'userName': {
        'S': 'ユーザ1'
    },
    'mailAddresses': {
        'L': [
            {
                'S': '[email protected]'
            },
            {
                'S': '[email protected]'
            }
        ]
    }
}

数値も文字列になってしまっています。
この形式のデータを

{
    'userId': 12345,
    'userName': 'ユーザ1',
    'mailAddresses': [
        '[email protected]',
        '[email protected]'
    ]
}

に直すコードが欲しかったので、書いてみました。

コード

remove_data_type の引数に、データ型を含むdictを渡すと、データ型に従って変換されたdictが返ります。
データ型毎に処理を書いているだけです。
一部、再帰が入っています。

import base64

def remove_data_type(record):
    return {k: remove_one_data_type(record[k]) for k in record}

def remove_one_data_type(data_type_and_value_dict):
    data_type, value = list(data_type_and_value_dict.items())[0]

    if data_type == 'S' or data_type == 'BOOL':
        return value

    if data_type == 'N':
        return float(value) if '.' in value else int(value)

    if data_type == 'B':
        return base64.b64decode(value)

    if data_type == 'NS':
        return set([float(v) if '.' in v else int(v) for v in value])

    if data_type == 'SS':
        return set(value)

    if data_type == 'BS':
        return set([base64.b64decode(v) for v in value])

    if data_type == 'M':
        return remove_data_type(value)

    if data_type == 'L':
        return [remove_one_data_type(v) for v in value]

    if data_type == 'NULL':
        return None

    raise Exception('Invalid data type: ' + data_type)

次のように呼び出します。

dynamodb_record = {
    'userId': {
        'N': '12345'
    },
    'userName': {
        'S': 'ユーザ1'
    },
    'mailAddresses': {
        'L': [
            {
                'S': '[email protected]'
            },
            {
                'S': '[email protected]'
            }
        ]
    }
}

converted_record = remove_data_type(dynamodb_record)
print(converted_record)
出力
{
    'userId': 12345,
    'userName': 'ユーザ1',
    'mailAddresses': [
        '[email protected]',
        '[email protected]'
    ]
}