Closed Luc1412 closed 1 year ago
I tried this against 1.13.1
, 1.14.0
, and the current 1.15.3
. It inserts into the collection user_data
Full script:
import asyncio
from abc import ABC
from typing import Optional
from motor.motor_asyncio import AsyncIOMotorClient
from beanie import Document, init_beanie
class UserEntry(Document, ABC):
id: int
value: Optional[str] = None
class Settings:
name = 'user_data'
use_state_management = True
async def main():
cli = AsyncIOMotorClient("mongodb://test:test@localhost:27017")
db = cli["test_find_one"]
await init_beanie(db, document_models=[UserEntry])
await UserEntry(id=2, value="Test").insert()
asyncio.run(main())
Please, correct my code to reproduce this error.
@roman-right Hi, I've got this issue as well. Before ~1.13 I used the following pattern: Have and extended base document class:
class BetterDocument(Document):
@classmethod
async def get_or_create(cls, data):
record = await cls.find_one(data)
if not record:
record = cls(**data)
await record.insert()
return record
@classmethod
async def get_or_update(cls, lookup, data):
record = await cls.find_one(lookup)
all_data = {**lookup, **data}
if not record:
record = cls(**all_data)
await record.insert()
else:
await record.update(all_data)
return record
@classmethod
async def get_edged(cls, lookup=None, default=None, direction=DESCENDING, sort_by="created"):
umongo_cursor = cls.find(lookup if lookup else {}).sort([(sort_by, direction)]).limit(1)
async for record in umongo_cursor:
return record
return default
@classmethod
async def get_latest(cls, lookup=None, default=None):
return await cls.get_edged(lookup, default, direction=DESCENDING)
@classmethod
async def get_earliest(cls, lookup=None, default=None):
return await cls.get_edged(lookup, default, direction=ASCENDING)
Then I inherited it for all my models in a project:
...
class PlayerIdentity(BaseModel):
external_id: Indexed(str, unique=True)
username: Indexed(str, unique=True)
demo_player: bool = False
class PlayerStatistics(BaseModel):
total_bets: int = 0
total_wins: int = 0
class Players(PlayerIdentity, PlayerStatistics, BetterDocument):
created: datetime = Field(default_factory=datetime.utcnow)
integration: Link[Integrations]
game_settings: PlayerGameSettings = Field(default_factory=PlayerGameSettings)
...
Everything worked perfectly until (I guess... didn't notice exactly) - v13.2.
After that version, I've got created a document called BetterDocument
Note: I didn't put this document to the document_models
list into the init_beanie
call
Fields of that document are all fields from all documents inherited from it + field called _class_id
with the name of the childer document with .
prefix, e.g.:
Thank you in advance! love beanie very much!
Juggerr thanks for sharing your case. I simplified my example strongly, so this might be the reason for not causing the issue.
I also subclassed the Document class (overwrite save_changes ti insert the doc if not exists) and called it Document. Seems like it's connected with that. I'll investigate that later.
Thank you for your input @Juggerr ,
Could you guys please make a script that I can run to see the problem? This bug looks pretty important but I can not reproduce it.
I use your snippets - put them into my dummy inserter and don't see this bug:
import asyncio
from datetime import datetime
from beanie import Document, init_beanie
from motor.motor_asyncio import AsyncIOMotorClient
from pydantic import BaseModel, Field
class BetterDocument(Document):
...
class PlayerIdentity(BaseModel):
one: str = "one"
class PlayerStatistics(BaseModel):
total_bets: int = 0
total_wins: int = 0
class Players(PlayerIdentity, PlayerStatistics, BetterDocument):
created: datetime = Field(default_factory=datetime.utcnow)
async def main():
cli = AsyncIOMotorClient("mongodb://beanie:beanie@localhost:27017")
db = cli["test_wrong_collection"]
await init_beanie(db, document_models=[Players])
await Players().insert()
asyncio.run(main())
Beanie versions: 1.13.1
, 1.14.0
, 1.15.x
Here is my example:
import asyncio
from pydantic import BaseModel, Field
from motor.motor_asyncio import AsyncIOMotorClient
from beanie import Document, init_beanie
class Mixin(BaseModel):
id: int = Field(..., ge=1, le=254)
class MyDoc(Document):
class Settings:
use_state_management = True
class Test(Mixin, MyDoc):
name: str
class Test2(MyDoc):
name: str
async def main():
client = AsyncIOMotorClient()
await init_beanie(database=client.b, document_models=[Test, Test2])
t1 = await Test(id=1, name='test').create()
print('Created', t1)
t2 = await Test2(name='test2').create()
print('Created', t2)
await t1.delete()
await t2.delete()
if __name__ == '__main__':
asyncio.run(main())
Beanie version 1.15.3. Using mongosh I see only "MyDoc" and "Test" collections.
Here is data inside MyDoc collection (before t2 is deleted):
b> db.MyDoc.find()
[
{
_id: ObjectId("637761b89fe3d9d138f0fbf8"),
_class_id: '.Test2',
name: 'test2'
}
]
This issue is related to the inheritance feature.
Thank you, @Vitalium ! Reproduced. This will be fixed today
@Luc1412 , @Juggerr , @Vitalium please try 1.15.4
works fine. Thanks for fixing it.
@roman-right It works, thank you very much!
Describe the bug Since 1.14.0 all my documents get inserted into one collection named "Documents". All documents also got a
_class_id
value with.UserEntry
To Reproduce
Expected behavior The document get's inserted into a "user_data" collection.
Additional context https://github.com/roman-right/beanie/compare/1.13.1...1.14.0