As ODMantic doesn't completely wrap the MongoDB API, some helpers are provided to be
enhance the usability while building raw queries and interacting with raw documents.
Since some field might have some customized key names,
you can get the key name associated to a field by using the unary + operator on the
model class. As well, to ease the use of aggregation pipelines where you might need to
reference your field ($field), you can double the operator (i.e use ++) to get the
field reference name.
fromdatetimeimportdatetimefrombsonimportObjectIdfromodmanticimportModelfromodmantic.exceptionsimportDocumentParsingErrorfromodmantic.fieldimportFieldclassUser(Model):name:strcreated_at:datetime=Field(default_factory=datetime.utcnow)document={"name":"Leeroy","_id":ObjectId("5f8352a87a733b8b18b0cb27")}try:User.parse_doc(document)exceptDocumentParsingErrorase:print(e)#> 1 validation error for User#> created_at#> key not found in document (type=value_error.keynotfoundindocument; key_name='created_at')#> (User instance details: id=ObjectId('5f8352a87a733b8b18b0cb27'))
In the previous example, using the default factories could create data inconsistencies
and in this case, it would probably be more suitable to perform a manual migration to
provide the correct values.
Still, the parse_doc_with_default_factoriesConfig option can be used to allow the use of the
default factories while parsing documents:
In the following example, we will demonstrate the use of the previous helpers to build
an aggregation pipeline. We will first consider a Rectangle model with two float
fields (height and length). We will then fetch the rectangles with an area that is
less than 10. To finish, we will reconstruct Rectangle instances from this query.
fromodmanticimportAIOEngine,ModelclassRectangle(Model):length:floatwidth:floatrectangles=[Rectangle(length=0.1,width=1),Rectangle(length=3.5,width=1),Rectangle(length=2.87,width=5.19),Rectangle(length=1,width=10),Rectangle(length=0.1,width=100),]engine=AIOEngine()awaitengine.save_all(rectangles)collection=engine.get_collection(Rectangle)pipeline=[]# Add an area fieldpipeline.append({"$addFields":{"area":{"$multiply":[++Rectangle.length,++Rectangle.width]}# Compute the area remotely}})# Filter only rectanges with an area lower than 10pipeline.append({"$match":{"area":{"$lt":10}}})# Project to keep only the defined fields (this step is optional)pipeline.append({"$project":{+Rectangle.length:True,+Rectangle.width:True,}# Specifying "area": False is unnecessary here})documents=awaitcollection.aggregate(pipeline).to_list(length=None)small_rectangles=[Rectangle.parse_doc(doc)fordocindocuments]print(small_rectangles)#> [#> Rectangle(id=ObjectId("..."), length=0.1, width=1.0),#> Rectangle(id=ObjectId("..."), length=3.5, width=1.0),#> ]