サーチ…


前書き

多くのアプリケーションでは、MongoDBのレコードをJSON形式でシリアル化する必要があります。レコードにdate、datetime、objectId、binary、codeなどのフィールドがある場合は、json.dumpsを使用するときにTypeError: not JSON serializableな例外でTypeError: not JSON serializableが発生しjson.dumps 。このトピックでは、これを克服する方法を示します。

json_utilの使用

json_utilには、ネイティブjsonメソッドをラップし、jsonとの間で明示的なBSON変換を提供する2つのヘルパメソッド( dumpsloads )が用意されています。

簡単な使い方

from bson.json_util import loads, dumps
record = db.movies.find_one()
json_str = dumps(record)
record2 = loads(json_str)

recordが:

{ 
    "_id" : ObjectId("5692a15524de1e0ce2dfcfa3"), 
    "title" : "Toy Story 4", 
    "released" : ISODate("2010-06-18T04:00:00Z") 
}

json_strは次のjson_strなります。

{
    "_id": {"$oid": "5692a15524de1e0ce2dfcfa3"},
    "title" : "Toy Story 4", 
    "released": {"$date": 1276833600000}
}

JSONOptions

JSONOptionsオブジェクトを介してdumpsの動作をカスタマイズすることは可能です。 DEFAULT_JSON_OPTIONSSTRICT_JSON_OPTIONS 2つのオプションがすでに利用可能です。

>>> bson.json_util.DEFAULT_JSON_OPTIONS
    JSONOptions(strict_number_long=False, datetime_representation=0,
     strict_uuid=False, document_class=dict, tz_aware=True, 
     uuid_representation=PYTHON_LEGACY, unicode_decode_error_handler='strict',
     tzinfo=<bson.tz_util.FixedOffset object at 0x7fc168a773d0>) 

さまざまなオプションを使用するには、次の操作を実行します。

  1. DEFAULT_JSON_OPTIONSオブジェクトを変更します。この場合、後続のすべてのdumps呼び出しでオプションが使用されます。

     from bson.json_util import DEFAULT_JSON_OPTIONS
     DEFAULT_JSON_OPTIONS.datetime_representation = 2
     dumps(record)
    
  2. 指定JSONOptionsへの呼び出しでdumps使っjson_optionsパラメータを:

     # using strict
     dumps(record, json_options=bson.json_util.STRICT_JSON_OPTIONS)
    
     # using a custom set of options
     from bson.json_util import JSONOptions
     options = JSONOptions() # options is a copy of DEFAULT_JSON_OPTIONS
     options.datetime_representation=2
     dumps(record, json_options=options)
    

JSONOptionsのパラメータはJSONOptionsです。

  • strict_number_long :trueの場合、Int64オブジェクトはMongoDB Extended JSONの厳密モードタイプNumberLong、つまり{"$numberLong": "<number>" }エンコードされます。それ以外の場合は、intとしてエンコードされます。デフォルトはFalseです。
  • datetime_representationdatetime.datetimeのインスタンスをエンコードするときに使用する表現。 0 => {"$date": <dateAsMilliseconds>} 、1 => {"$date": {"$numberLong": "<dateAsMilliseconds>"}} 、2 => {"$date": "<ISO-8601>"}
  • strict_uuid :trueの場合、uuid.UUIDオブジェクトはMongoDB Extended JSONのStrictモードのバイナリにエンコードされます。それ以外の場合は、 {"$uuid": "<hex>" }としてエンコードされます。デフォルトはFalseです。
  • document_class :loads()によって返されたBSONドキュメントは、このクラスのインスタンスにデコードされます。 collections.MutableMappingのサブクラスでなければなりません。デフォルトはdictになります。
  • uuid_representationuuid.UUIDのインスタンスをエンコードおよびデコードするときに使用するBSON表現。デフォルトはPYTHON_LEGACYです。
  • tz_aware :trueの場合、MongoDB Extended JSONのStrictモードのDateは、datetime.datetimeのタイムゾーン対応インスタンスにデコードされます。それ以外の場合、彼らは素朴になります。デフォルトはTrueです。
  • tzinfo :datetimeオブジェクトをデコードするタイムゾーンを指定するdatetime.tzinfoサブクラス。デフォルトはutcです。

python-bsonjsの使用

python-bsonjsは PyMongoに依存しないとの素晴らしいパフォーマンスの改善を提供することができjson_util

bsonjsは JSONにBSONをデコードしBSONにJSONをコードするPyMongoのjson_utilよりおおよそ10-15x高速です。

ご了承ください:

  • bsonjを効果的に使用するには、 RawBSONDocument直接作業することをお勧めしRawBSONDocument
  • 日付はLEGACY表現、すなわち{"$date": <dateAsMilliseconds>}を使って符号化されます。現在、それを変更するオプションはありません。

インストール

pip install python-bsonjs

使用法

bsonjsを最大限に活用するには、 RawBSONDocumentクラスを使用するようにデータベースを構成します。次に、 dumpsを使用してbsonのrawバイトをjsonに変換し、 loadsしてjsonをbsonのrawバイトに変換します。

import pymongo
import bsonjs
from pymongo import MongoClient
from bson.raw_bson import RawBSONDocument

# configure mongo to use the RawBSONDocument representation
db = pymongo.MongoClient(document_class=RawBSONDocument).samples
# convert json to a bson record
json_record = '{"_id": "some id", "title": "Awesome Movie"}' 
raw_bson = bsonjs.loads(json_record)
bson_record = RawBSONDocument(raw_bson)
# insert the record
result = db.movies.insert_one(bson_record)
print(result.acknowledged)

# find some record
bson_record2 = db.movies.find_one()
# convert the record to json
json_record2 = bsonjs.dumps(bson_record2.raw)
print(json_record2)

カスタムハンドラでjsonモジュールを使用する

mongoの結果をjsonにシリアライズするだけであれば、 jsonモジュールを使用することができます。ただし、シリアライズ不可能なフィールド型を処理するカスタムハンドラを定義する必要があります。 1つの利点は、datetime表現のような特定のフィールドをどのようにエンコードするかを最大限に活用できることです。

iso表現とidを16進文字列として使用して日付をエンコードするハンドラを次に示します。

import pymongo
import json 
import datetime
import bson.objectid

def my_handler(x):
    if isinstance(x, datetime.datetime):
        return x.isoformat()
    elif isinstance(x, bson.objectid.ObjectId):
        return str(x)
    else:
        raise TypeError(x)

db = pymongo.MongoClient().samples
record = db.movies.find_one()
# {u'_id': ObjectId('5692a15524de1e0ce2dfcfa3'), u'title': u'Toy Story 4',
#   u'released': datetime.datetime(2010, 6, 18, 4, 0),}

json_record = json.dumps(record, default=my_handler)
# '{"_id": "5692a15524de1e0ce2dfcfa3", "title": "Toy Story 4", 
#    "released": "2010-06-18T04:00:00"}'


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow