Recherche…


Introduction

Dans de nombreuses applications, les enregistrements de MongoDB doivent être sérialisés au format JSON. Si vos enregistrements ont des champs de type date, datetime, objectId, binary, code, etc., vous rencontrez TypeError: not JSON serializable exceptions TypeError: not JSON serializable lors de l'utilisation de json.dumps . Cette rubrique montre comment surmonter cela.

Utiliser json_util

json_util fournit deux méthodes d'assistance, des dumps et des loads , qui encapsulent les méthodes json natives et fournissent une conversion BSON explicite vers et depuis json.

Usage simple

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

si record est:

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

alors json_str devient:

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

JSONOptions

Il est possible de personnaliser le comportement des dumps au moyen d' un JSONOptions objet. Deux ensembles d'options sont déjà disponibles: DEFAULT_JSON_OPTIONS et 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>) 

Pour utiliser différentes options, vous pouvez:

  1. modifiez l'objet DEFAULT_JSON_OPTIONS . Dans ce cas, les options seront utilisées pour tous les appels suivants aux dumps :

     from bson.json_util import DEFAULT_JSON_OPTIONS
     DEFAULT_JSON_OPTIONS.datetime_representation = 2
     dumps(record)
    
  2. spécifier un JSONOptions dans un appel à dumps utilisant le paramètre 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)
    

Les paramètres de JSONOptions sont les suivants:

  • strict_number_long : Si true, les objets Int64 sont codés dans le type Strict NumberLong du mode Strict de MongoDB Extended JSON, c'est-à-dire {"$numberLong": "<number>" } . Sinon, ils seront encodés en int. La valeur par défaut est False.
  • datetime_representation : représentation à utiliser lors du codage des instances de datetime.datetime. 0 => {"$date": <dateAsMilliseconds>} , 1 => {"$date": {"$numberLong": "<dateAsMilliseconds>"}} , 2 => {"$date": "<ISO-8601>"}
  • strict_uuid : Si true, l'objet uuid.UUID est codé dans le type de mode Strict Binary de MongoDB Extended JSON. Sinon, il sera codé comme {"$uuid": "<hex>" } . La valeur par défaut est False.
  • document_class : Les documents BSON renvoyés par load () seront décodés en une instance de cette classe. Doit être une sous-classe de collections.MutableMapping. Par défaut, dict.
  • uuid_representation : représentation BSON à utiliser lors du codage et du décodage des instances de uuid.UUID. La valeur par défaut est PYTHON_LEGACY.
  • tz_aware : Si la valeur est true, le type de mode Strict de MongoDB Extended JSON Date sera décodé en instances de datetime.datetime identifiées par le fuseau horaire. Sinon, ils seront naïfs. La valeur par défaut est True.
  • tzinfo : Une sous-classe datetime.tzinfo qui spécifie le fuseau horaire à partir duquel les objets datetime doivent être décodés. La valeur par défaut est utc.

Utiliser python-bsonjs

python-bsonjs ne dépend pas de PyMongo et peut offrir une amélioration des performances par rapport à json_util :

bsonjs est environ 10 à 15 fois plus rapide que json_util de PyMongo pour décoder BSON en JSON et encoder JSON en BSON.

Notez que:

  • pour utiliser efficacement bsonjs, il est recommandé de travailler directement avec RawBSONDocument
  • les dates sont codées en utilisant la représentation LEGACY, c'est-à-dire {"$date": <dateAsMilliseconds>} . Il n'y a actuellement aucune option pour changer cela.

Installation

pip install python-bsonjs

Usage

Pour tirer pleinement parti des bsonjs, configurez la base de données pour utiliser la classe RawBSONDocument . Ensuite, utilisez dumps pour convertir des octets bruts bson en json et des loads pour convertir json en octets bruts 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)

Utilisation du module json avec des gestionnaires personnalisés

Si tout ce dont vous avez besoin est la sérialisation des résultats de mongo dans json, il est possible d'utiliser le module json , à condition que vous définissiez des gestionnaires personnalisés pour gérer les types de champs non sérialisables. Un avantage est que vous disposez de toute la puissance nécessaire pour encoder des champs spécifiques, tels que la représentation datetime.

Voici un gestionnaire qui code les dates en utilisant la représentation iso et l'ID sous forme de chaîne hexadécimale:

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow