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:

  1. ändra objektet DEFAULT_JSON_OPTIONS . I detta fall kommer alternativen att användas för alla efterföljande uppmaningar till dumps :

     from bson.json_util import DEFAULT_JSON_OPTIONS
     DEFAULT_JSON_OPTIONS.datetime_representation = 2
     dumps(record)
    
  2. specificera en JSONOptions i ett samtal till dumps med parametern 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)
    

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"}'


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow