Buscar..


Introducción

En muchas aplicaciones, los registros de MongoDB deben ser serializados en formato JSON. Si sus registros tienen campos de tipo fecha, fecha y hora, objectId, binario, código, etc., se encontrará con TypeError: not JSON serializable excepciones TypeError: not JSON serializable al usar json.dumps . Este tema muestra cómo superar esto.

Usando json_util

json_util proporciona dos métodos de ayuda, dumps y loads , que envuelven los métodos nativos de json y proporcionan una conversión BSON explícita desde y hacia json.

Uso simple

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

si el record es:

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

entonces json_str convierte en:

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

JSONOptions

Es posible personalizar el comportamiento de los dumps través de un objeto JSONOptions . Ya hay dos conjuntos de opciones disponibles: DEFAULT_JSON_OPTIONS y 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>) 

Para usar diferentes opciones, puedes:

  1. Modificar el objeto DEFAULT_JSON_OPTIONS . En este caso, las opciones se utilizarán para todas las llamadas posteriores a dumps :

     from bson.json_util import DEFAULT_JSON_OPTIONS
     DEFAULT_JSON_OPTIONS.datetime_representation = 2
     dumps(record)
    
  2. especifique un JSONOptions en una llamada a dumps usando el parámetro 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)
    

Los parámetros de JSONOptions son:

  • strict_number_long : Si es verdadero, los objetos Int64 están codificados en el tipo de modo Estricto JSON de MongoDB Extended JSON, es decir, {"$numberLong": "<number>" } . De lo contrario, serán codificados como un int. Por defecto es falso.
  • datetime_representation : la representación a usar cuando se codifican instancias de datetime.datetime. 0 => {"$date": <dateAsMilliseconds>} , 1 => {"$date": {"$numberLong": "<dateAsMilliseconds>"}} , 2 => {"$date": "<ISO-8601>"}
  • strict_uuid : Si es verdadero, el objeto uUidIDID se codifica en el modo Binario de modo estricto JSON de MongoDB. De lo contrario, se codificará como {"$uuid": "<hex>" } . Por defecto es falso.
  • document_class : los documentos BSON devueltos por loads () se descodificarán a una instancia de esta clase. Debe ser una subclase de colecciones.MutableMapping. El valor predeterminado es dict.
  • uuid_representation : la representación de BSON que se usará al codificar y decodificar instancias de uuidIDID. Por defecto es PYTHON_LEGACY.
  • tz_aware : si es verdadero, la fecha del tipo de modo estricto de JSON extendido de MongoDB se decodificará a las instancias de datetime.datetime conscientes de la zona horaria. De lo contrario serán ingenuos. El valor predeterminado es True.
  • tzinfo : una subclase de datetime.tzinfo que especifica la zona horaria desde la que se deben decodificar los objetos de fecha y hora. Por defecto es utc.

Usando python-bsonjs

python-bsonjs no depende de PyMongo y puede ofrecer una buena mejora de rendimiento sobre json_util :

bsonjs es aproximadamente 10-15 veces más rápido que json_util de PyMongo en la decodificación de BSON a JSON y la codificación de JSON a BSON.

Tenga en cuenta que:

  • para usar bsonjs de manera efectiva, se recomienda trabajar directamente con RawBSONDocument
  • las fechas se codifican utilizando la representación de LEGACY, es decir, {"$date": <dateAsMilliseconds>} . Actualmente no hay opciones para cambiar eso.

Instalación

pip install python-bsonjs

Uso

Para aprovechar al máximo los bsonjs, configure la base de datos para utilizar la clase RawBSONDocument . Luego, usa los dumps para convertir los bytes sin procesar de bson a json y las loads para convertir los bytes sin procesar de json a bson:

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)

Usando el módulo json con manejadores personalizados.

Si todo lo que necesita es serializar los resultados de mongo en json, es posible usar el módulo json , siempre que defina controladores personalizados para tratar con los tipos de campos no serializables. Una ventaja es que tiene plena capacidad para codificar campos específicos, como la representación de fecha y hora.

Aquí hay un controlador que codifica fechas usando la representación iso y el id como una cadena hexadecimal:

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow