odmantic
odmantic copied to clipboard
Datetime not updating and not updating frequently
Hi all,
not sure if this is my pydantic model configuration problem, but i found some datetime fields not updating correctly and consistently (inside Mongodb Compass)
Bug
2 Problems:
-
When using Pydantic V2.5 having the
@model_validator
or@field_validator
decorator in the respective model to handle datetime update, Mongodb engine does not updatedatetime
fields withsession.save()
. I tried / experimented using this for multiple fields for other datatypes, i.e.,string
, andUUID
, both update consistently into the database. -
Using
<collection>.model_update()
as recommended in the docs, does it correctly to updatedatetime
fields. However the frequency of update is inconsistent.
Temporary fix
To overcome this (for the time being), i used <collection>.model_copy()
to make a quick copy with session.save()
. This now updates the document datetime field at the consistent rate.
Things to note: I'm saving / updating documents in mongodb at the rate of 1 doc per sec and 3 doc per sec.
What i noticed after digging around is, inside the _BaseODMModel
it does not capture the fields as __fields_modified__
and is_type_mutable
returns as false. Not sure if that helps
Current Behavior
### Schema
from odmantic import Model, Field, bson
from odmantic.bson import BSON_TYPES_ENCODERS
from odmantic.config import ODMConfigDict
from pydantic import field_validator, UUID4, model_validator, BaseModel
from bson.binary import Binary
from datetime import datetime
from typing import Any
from uuid import uuid4
from typing_extensions import Self
class BookCollection(Model):
id: UUID4 = Field(primary_field=True, default_factory=uuid4)
book_id: UUID4
borrorwer: str
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
model_config = ODMConfigDict(
collection="BOOK_COLLECTION",
)
@model_validator(mode="before") # type: ignore
def update_field_updated_at(cls, input: dict) -> dict:
input["updated_at"] = datetime.utcnow()
return input
# > This one works. (Above does not), Also did this using @field_validator, only book_id works, not for updated_at (datetime)
# @model_validator(mode="before")
# def validate_field_book_id(cls, input: dict) -> dict:
# input["book_id"] = uuid4()
# return input
@asynccontextmanager
async def get_mongodb() -> AsyncGenerator[MongoDB, None]:
try:
mongodb = MongoDB()
# 01 Start session
await mongodb.start_session()
yield mongodb
finally:
# 02 gracefully end session
await mongodb.end_session()
def func_update_id(new_id: string) -> None:
async with get_mongodb() as mongodb:
result = await mongodb.session.find_one(
BookCollection,
BookCollection.book_id == UUID("69e4ea5b-1751-4579-abb1-60c31e939c0f")
)
if result is None:
logger.error("Book Doc not found!")
return None
else:
# Method 1
# Bug 1 > datetime does not save into mongodb, but returned model shows its updated.
result.model_update()
result.book_id = new_id
data = await mongodb.session.save(result)
# Method 2
# Bug 2 > datetime saves into mongodb, but not consistently.
result.model_update({"book_id": new_id})
data = await mongodb.session.save(result)
# quick fix
result.book_id = new_id
data = await mongodb.session.save(result.model_copy())
### Expected behavior
To update `datetime` fields in mongodb engine at a consistent rate using pydantic decorators
### Environment
- ODMantic version: "^1.0.0"
- MongoDB version: [6.00](mongo:6.0) Docker
- Pydantic: ^2.5
- Mongodb Compass: 1.35