PyMongo
Konvertering mellan BSON och JSON
Sök…
Introduktion
I många applikationer måste poster från MongoDB serialiseras i JSON-format. Om dina poster har fält av typdatum, datetime, objectId, binär, kod osv. TypeError: not JSON serializable
du att möta TypeError: not JSON serializable
undantag när du använder json.dumps
. Detta ämne visar hur man kan övervinna detta.
Med json_util
json_util tillhandahåller två hjälpmetoder, dumps
och loads
, som slår in de ursprungliga json-metoderna och ger explicita BSON-konvertering till och från json.
Enkel användning
from bson.json_util import loads, dumps
record = db.movies.find_one()
json_str = dumps(record)
record2 = loads(json_str)
om record
är:
{
"_id" : ObjectId("5692a15524de1e0ce2dfcfa3"),
"title" : "Toy Story 4",
"released" : ISODate("2010-06-18T04:00:00Z")
}
då blir json_str
:
{
"_id": {"$oid": "5692a15524de1e0ce2dfcfa3"},
"title" : "Toy Story 4",
"released": {"$date": 1276833600000}
}
JSONOptions
Det är möjligt att anpassa dumps
beteende via ett JSONOptions
objekt. Två uppsättningar alternativ finns redan tillgängliga: DEFAULT_JSON_OPTIONS
och STRICT_JSON_OPTIONS
.
>>> 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>)
För att använda olika alternativ kan du:
ändra objektet
DEFAULT_JSON_OPTIONS
. I detta fall kommer alternativen att användas för alla efterföljande uppmaningar tilldumps
:from bson.json_util import DEFAULT_JSON_OPTIONS DEFAULT_JSON_OPTIONS.datetime_representation = 2 dumps(record)
specificera en
JSONOptions
i ett samtal tilldumps
med parameternjson_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)
Parametrarna för JSONOptions
är:
- string_number_long : Om det är sant, kodas Int64-objekt till MongoDB Extended JSONs strikta lägetyp NumberLong, dvs
{"$numberLong": "<number>" }
. Annars kommer de att kodas som ett int. Standardvärden är falska. - datetime_representation : Representationen som ska användas vid kodning av instanser av datetime.datetime. 0 =>
{"$date": <dateAsMilliseconds>}
, 1 =>{"$date": {"$numberLong": "<dateAsMilliseconds>"}}
, 2 =>{"$date": "<ISO-8601>"}
- string_uuid : Om det är sant, kodas uuid.UUID-objekt till MongoDB Extended JSON: s striktläge typ Binary. Annars kommer den att kodas som
{"$uuid": "<hex>" }
. Standardvärden är falska. - document_class : BSON-dokument som returneras av laster () avkodas till en instans av denna klass. Måste vara en underklass av samlingar. MutableMapping. Standardvärdet för dict.
- uuid_representation : BSON-representation som ska användas vid kodning och avkodning av instanser av uuid.UUID. Standard är PYTHON_LEGACY.
- tz_aware : Om det är sant, kommer MongoDB Utökad JSONs strikt läge typ Datum avkodas till tidszon medvetna instanser av datetime.datetime. Annars kommer de att vara naiva. Standardvärdet är sant.
- tzinfo : En
datetime.tzinfo
underklass som anger tidszonen från vilken datetime-objekt ska avkodas. Standardvärden för utc.
Använda python-bsonjs
python-bsonjs är inte beroende av PyMongo och kan erbjuda en fin prestandaförbättring jämfört med json_util
:
bsonjs är ungefär 10-15 gånger snabbare än PyMongos json_util vid avkodning av BSON till JSON och kodning av JSON till BSON.
Anteckna det:
- För att använda bsonjs effektivt rekommenderas det att arbeta direkt med
RawBSONDocument
- datum kodas med LEGACY-representationen, dvs
{"$date": <dateAsMilliseconds>}
. Det finns för närvarande inga alternativ för att ändra det.
Installation
pip install python-bsonjs
Användande
För att dra full nytta av bsonjs konfigurerar du databasen för att använda RawBSONDocument
klassen. Använd sedan dumps
att konvertera bson raw byte till json och loads
att konvertera json till bson raw byte:
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)
Använda json-modulen med anpassade hanterare
Om allt du behöver är att serialisera mongo-resultat till json, är det möjligt att använda json
modulen, förutsatt att du definierar anpassade hanterare för att hantera fälttyper som inte kan serialiseras. En fördel är att du har full kraft på hur du kodar specifika fält, som datatrepresentationen.
Här är en hanterare som kodar datum med iso-representation och id som en hexadecimal sträng:
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"}'