如何使用MongoEngine ReferenceField为2个集合使用相同的ObjectId?

时间:2013-04-04 10:53:01

标签: mongodb one-to-one mongoengine

我有一个相当繁重的User文档类,我想将它分成两部分:用户的个人资料(姓名和头像)位于UserProfile文档中,其余部分位于{{} 1}}文档,像这样(使用MongoEngine):

User

我想为UserProfile和User提供相同的ObjectId,因此我只需要一个ObjectId来引用User和UserProfile。毕竟,这真的是一对一的关系,而且由于用户可以创作很多帖子,我不想将自己的个人资料嵌入帖子本身。在创建用户文档时,我会立即创建相应的配置文件,如下所示:

from mongoengine import *

class User(Document):
    login = StringField()
    password = StringField()
    posts = ListField(ReferenceField("Post", dbref = False))
    #... a bunch of other fields

class UserProfile(Document):
    name = StringField()
    avatar = URLField()

到目前为止一切顺利。现在我有一个john = User.objects.create(login = "john", password = "super!password") john_profile = UserProfile.objects.create(id = john.id, name = "John Smith", avatar = "http://www.example.com/img/photo.jpg") 文档,其Post字段引用了author文档:

User

我想基于相同的ObjectId添加class Post(Document): author = ReferenceField("User", dbref = False) text = StringField() 引用。我试过这个:

author_profile

但我得到以下例外:

class Post(Document):
    author = ReferenceField("User", dbref = False)
    author_profile = ReferenceField("User", db_field = "author", dbref = False)
    text = StringField()

所以我似乎必须“手动”这样做。也许是这样的事情:

mongoengine.base.InvalidDocumentError: Multiple db_fields defined for: author

我想这不是那么糟糕,但是没有更好的解决方案吗?

感谢。

注意:我阅读了关于一对一关系的mongodb documentation以及mongoengine ReferenceField documentation,但它对这个具体问题没有帮助。

2 个答案:

答案 0 :(得分:0)

您必须存储两次相同的ID才能执行此操作:

class Post(Document):
    author = ReferenceField("User", dbref = False)
    author_profile = ReferenceField("UserProfile", dbref = False)
    text = StringField()

我不确定这是否会给您的解决方案带来任何好处 - 解除引用的查询数量可能会有所改善,但我必须对其进行测试!

答案 1 :(得分:0)

我最后写了这个:

def user_profile(reference_name):
    attrib_name = "_" + reference_name + "_profile"
    def user_profile_getter(self):
        if not hasattr(self, attrib_name):
            reference = self._data.get(reference_name, None)
            if not reference:
                return None
            setattr(self, attrib_name, UserProfile.objects.get(reference.id))
        return getattr(self, attrib_name)
    return property(user_profile_getter)

我的Post课程现在看起来像这样:

class Post(Document):
    author = ReferenceField("User", dbref = False)
    author_profile = user_profile("author")
    text = StringField()

每当我添加指向ReferenceField类的User时,我也会添加user_profile(只读)引用。请注意,如果您只访问author_profile,则不会加载author,反之亦然。