Say we have a Pydantic object that we want to insert into MongoDB:
from bson import ObjectId
from datetime import datetime
class A(pydantic.BaseModel):
w: ObjectId
x: datetime
The built-in BaseModel.json
method does not handle BSON documents, so I need to pass a custom encoder:
from bson import json_util
a = A(w=ObjectId("123"), x=datetime(2023,1,1))
a.json(encoder=json_util.dumps, exclude_none=True)
Because of default behavior for json_util.dumps
, above results in a very ugly BSON where dates are shown as either a dictionary ({"$date": "2023-01-01"}
) or a timestamp ({"$date": {"$numberLong": "12314215"}}
).
Found this documentation on json_util
, and I tried to pass in json_options
to pydantic.BaseModel.json
... but it does not work.
TypeError: JSONEncoder.__init__() got an unexpected keyword argument 'json_options'
But I just passed in a custom encoder... The kwarg should be passed to json_util.dumps
, but clearly that is not the case here.
Alternatively, I could convert the whole thing to just a string. But I wanted to properly encode my document before insert into MongoDB. I don't want my ObjectId to be converted to a string.
The data serializes just fine, but looking at these date values in Mongo is just uncomfortable.
This should not be this difficult... What am I missing?
Alternatively, I could convert the whole thing to just a string. But I wanted to properly encode my document before insert into MongoDB. I don't want my ObjectId to be converted to a string.
The data serializes just fine, but looking at these date values in Mongo is just uncomfortable.
Use pydantic's dict()
method to convert your model into a dictionary, then insert that into MongoDB:
from bson import ObjectId
from datetime import datetime
import pydantic
import pymongo
db = pymongo.MongoClient()['test']
class A(pydantic.BaseModel):
class Config:
arbitrary_types_allowed = True
w: ObjectId
x: datetime
a = A(w=ObjectId(), x=datetime(2023, 1, 1))
db['mycollection'].insert_one(a.dict())
mongosh:
test> db.mycollection.findOne()
{
_id: ObjectId("649627207cac51eab98924cb"),
w: ObjectId("649627207cac51eab98924ca"),
x: ISODate("2023-01-01T00:00:00.000Z")
}