odmantic icon indicating copy to clipboard operation
odmantic copied to clipboard

Datetime not updating and not updating frequently

Open TyroneTang opened this issue 1 year ago • 0 comments

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:

  1. 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 update datetime fields with session.save() . I tried / experimented using this for multiple fields for other datatypes, i.e., string, and UUID, both update consistently into the database.

  2. Using <collection>.model_update() as recommended in the docs, does it correctly to update datetime 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

TyroneTang avatar Feb 24 '24 08:02 TyroneTang