BeanieODM / beanie

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

Nested document links #277

Closed Purfakt closed 1 year ago

Purfakt commented 2 years ago

What doesn't work

As per the documentation, only top level Links are fully supported in beanie. This means nested linking doesn't work properly. The following doesn't work: A and B are documents. A has a list of C and C contains a Link[B].

Expected behaviour

In MongoDB, I would expect to see a list of C containing DBRefs of B inside of the document A

Current behavious

In MongoDB, A has a list of C, but C contains full copies of B.

Reproducible example

This example contains something similar to my faulty code.

import asyncio
from uuid import UUID, uuid4
from pydantic import BaseModel, Field
from motor.motor_asyncio import AsyncIOMotorClient
from beanie import Document, Link, WriteRules, init_beanie
from beanie.operators import In

class Window(BaseModel):
    name: str

class Room(BaseModel):
    name: str
    window: Window

class House(BaseModel):
    name: str
    rooms: list[Room]

class WindowDocument(Document, Window):
    id: UUID = Field(default_factory=uuid4)

    class Collection:
        name = "window"

class RoomWithLink(Room):
    windows: Link[WindowDocument]

class HouseDocument(Document, House):
    rooms: list[RoomWithLink] = list()

    class Collection:
        name = "house"

    @classmethod
    async def add_window(
        cls,
        house_id: UUID,
        window_ids: list[UUID],
        room_name: str,
    ):
        house = await cls.find_one(cls.id == house_id)
        windows = await WindowDocument.find(In(cls.id, window_ids)).to_list()

        for window in windows:
            room = Room(window=window, name=room_name)
            house.rooms.append(room)
        await house.save(link_rule=WriteRules.WRITE)

async def initialize():
    await init_beanie(
        database=AsyncIOMotorClient("localhost:27017", 4000)["my-db"],
        document_models=[HouseDocument, WindowDocument],
    )

async def main():
    await initialize()
    window = Window(name="nice window")
    room_name = "living room"
    house = House(name="my house", rooms=list())

    window_doc = await WindowDocument(name=window.name).create()
    house_doc = await HouseDocument(name=house.name, rooms=house.rooms).create()

    await HouseDocument.add_window(
        house_id=house_doc.id,
        window_ids=[window_doc.id],
        room_name=room_name,
    )

asyncio.run(main())
dave4jr commented 2 years ago

@roman-right Hey Roman, really cool library, thanks for all the hard work on this. Just curious, any thoughts as to when this issues will be fixed? Thanks a bunch!

roman-right commented 2 years ago

Hey @dave4jr , This particular issue will take time to solve, bc it is related to MongoDB limitations. So, it is hard to predict, as I don't have a good solution even in theory. In general, I'm focused on another one open source project right now. I plan to publish it next week and get back to Beanie's issues after.

github-actions[bot] commented 1 year ago

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

github-actions[bot] commented 1 year ago

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