人間が確認するためにbsonを文字列にdumpしたいことがある。
bsonはjsonではない
bsonはjsonではないのでjson.dumpsは使えない。
import json import bson from collections import ChainMap person = ChainMap({"name": "foo"}, ChainMap({"age": 20}, {"_id": bson.ObjectId()})) try: print(json.dumps(person)) except Exception as e: print("hmm", e)
エラーになる。
hmm ChainMap({'name': 'foo'}, ChainMap({'age': 20}, {'_id': ObjectId('5950d8f10ccee07b8eb563dc')})) is not JSON serializable
json.dumpsに小細工すると見た目が悪い
json.dumpsにdefaultなどを渡して小細工をすると文字列化はできるのだけれど。例えばdictではなくChainMapやOrderedDictみたいなMappingの型の値の場合に見た目が良くない。
print(json.dumps(person, indent=2, ensure_ascii=False, default=str))
これはよくない。
"ChainMap({'name': 'foo'}, ChainMap({'age': 20}, {'_id': ObjectId('5950d9560ccee07c0ec0d91f')}))"
もう少し真面目に書くとマシにはなる。
def default(d): if hasattr(d, "keys"): return dict(d) else: return str(d) print(json.dumps(person, indent=2, ensure_ascii=False, default=default))
マシにはなる。
{
"_id": "5950d9560ccee07c0ec0d91f",
"name": "foo",
"age": 20
}
bson.json_utilが便利かもしれない
bson.json_utilが便利かもしれない。
import bson.json_util as u print(u.dumps(person, indent=2, ensure_ascii=False))
dumpsに対応するloadsもあったりはするのでこちらのほうが良いのかもしれない(とは言え、こちらの形式もMongoBoosterなどでおなじみの表現じゃないところがちょっと困る(もう少しbsonにencodingした時の状態に近い感じ))。
{
"name": "foo",
"_id": {
"$oid": "5950d99a0ccee07c50d97fd2"
},
"age": 20
}