BeanieODM / beanie

Asynchronous Python ODM for MongoDB
http://beanie-odm.dev/
Apache License 2.0
1.99k stars 211 forks source link

[BUG] save_changes doesn't save dict data correctly when dictionary key has "." in it's value #729

Closed yutongp closed 7 months ago

yutongp commented 11 months ago

Describe the bug save_changes doesn't save data correctly when data is a dictionary and the key has "." in it's value

To Reproduce

from beanie import Document, init_beanie
from pydantic import HttpUrl
from motor.motor_asyncio import AsyncIOMotorClient
import os

class Data(Document):
    data : dict

    class Settings:
        use_state_management = True
        state_management_save_previous = True

MONGO_URI = os.environ.get("MONGO_URI", "mongodb://localhost:27017/")

async def config_db():
    # Create Motor client
    client = AsyncIOMotorClient(MONGO_URI)

    # Init beanie with the Product document class
    await init_beanie(
        database=client["test"],
        document_models=[
            Data,
        ],
    )

await config_db()

data = await Data(data={"https://www.google.com/foo": "bar"}).save()
data.data = {"https://www.google.com/hello": "world"}
await data.save_changes()

Expected behavior A clear and concise description of what you expected to happen. Data should be stored as

Data(id=ObjectId('...'), revision_id=None, data={'https://www.google.com/foo': 'bar', 'https://www.google.com/hello': 'world'})

However, beanie split the https://www.google.com/hello into nested level object and stored the data as

Data(id=ObjectId('...'), revision_id=None, data={'https://www.google.com/foo': 'bar', 'https://www/': {'google': {'com/hello': 'world'}}})

Additional context Add any other context about the problem here.

github-actions[bot] commented 10 months ago

This issue is stale because it has been open 30 days with no activity.

roman-right commented 10 months ago

Hi @yutongp , Sorry for the late reply. I'll fix it during the next bug-fixing session. Thank you for the catch

roman-right commented 9 months ago

Hi @yutongp , This is a VERY weird bug. Thank you for the catch! The problem is with the $set operator of MongoDB. It looks like it doesn't like dots. You can reproduce it with:

await data.update({"$set": {"https://www.google.com/foo": "worlds"}})

I'd suggest applying a function to not include dots to keys. Like this:

    key = "https://www.google.com/foo".replace(".", "%2E")
    data = await Data(data={key: "bar"}).save()
    data.data = {key: "world"}
    await data.save_changes()
github-actions[bot] commented 8 months ago

This issue is stale because it has been open 30 days with no activity.

github-actions[bot] commented 7 months ago

This issue was closed because it has been stalled for 14 days with no activity.