STEAM PLACE

エンジニアリングとマネジメント

DynamoDB x Python / Decimal を登録する

 JSON と Python のマッピング

JSON と Python の dict は以下のようにマッピングされている。

JSON Python
object dict
array list
string unicode
number (int) int, long
number(real) float
true True
false False
null None

そのため、JSON を json.loads() でパースして、そのまま dynamo.put_item() で登録すると前述の型で登録される。この際に float 型があると下記のように怒られる。

Float types are not supported. Use Decimal types instead.

Python の float はそのままでは DynamoDB に登録できないのである。
代わりに Decimal で登録する必要がある。

 Float ではなく Decimal として登録するには?

Float を Decimal にマッピングさせる必要がある。
例えば以下の様なデータを登録するとする。

json_data
 
{"Timestamp": "20160323T203501.000+0900", "x": -0.279938, "y": -0.754028, "z": -0.607758 }

JSON をパースする際に下記のように parse_float=decimal.Decimal をつければよい。

 
import json
import boto3
import decimal
#...省略
item = json.loads(json_data, parse_float=decimal.Decimal)
dynamo = boto3.resource('dynamodb').Table('ThisIsJustTest')
dynamo.put_item(Item = item)

 補足

Python 公式にも記載されていたが、ぐぐってもすぐに情報が出なかったので記事にした。

 

18.2. json — JSON encoder and decoder — Python 2.7.18 documentation
https://docs.python.org

 

parse_float, if specified, will be called with the string of every JSON float to be decoded. By default, this is equivalent to float(num_str). This can be used to use another datatype or parser for JSON floats (e.g. decimal.Decimal).

 
json.loads(s[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]])

AWS のドキュメントにもサラッとのっていた。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/gettingstartedguide/GettingStarted.Python.02.html

 Decimal から戻すとき

以下のようなやり方紹介されている。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/gettingstartedguide/GettingStarted.Python.03.html
http://stackoverflow.com/questions/1960516/python-json-serialize-a-decimal-object