pythonmongodbmongoengine

Subclassing document in separate collections in Mongoengine


I have a collection in Mongoengine with long list of fields which contains some documents:

class Component(Document):
    name = StringField(unique=True)
    title = StringField(required=True)
    description = StringField(default='')
    # And so on...

Now I want another collection similar to the first collection with some extra stuffs. So I used allow_inheritance in the first collection for subclassing:

class Component(Document):
    name = StringField(unique=True)
    title = StringField(required=True)
    description = StringField(default='')
    # And so on...
    meta = {'allow_inheritance': True}

class ChildComponent(Component):
    extra_stuff = StringField()

But as the documents mentions, this way all the data will save in the same collection.

So I tried adding abstract to meta in the parent document, so I can have two separate collections.

class Component(Document):
    name = StringField(unique=True)
    title = StringField(required=True)
    description = StringField(default='')
    # And so on...
    meta = {'allow_inheritance': True, 'abstract': True}

But now when I try to get the documents from Component using Component.objects().all() I get this error:

AttributeError: type object 'Component' has no attribute 'objects'

Should I create a base document and abstract my two collections from it or there's simpler way to solve this issue?

UPDATE

Even if I create a base class and inherit both classes from it:

class BaseComponent(Document):
    name = StringField(unique=True)
    title = StringField(required=True)
    description = StringField(default='')
    # And so on...
    meta = {'allow_inheritance': True, 'abstract': True}

class Component(BaseComponent):
    pass

class ChildComponent(BaseComponent):
    extra_stuff = StringField()

When I try Component.objects.all(), the result will be and empty list.

UPDATE 2 If I add a component with .save() I can get that one with Component.objects.all(). But what about the rest of the documents which are already saved in that collection? How can I restore them?


Solution

  • Since I got no answer, I've found a work around for it. When using abstract in meta, the child collections get an extra field called _cls with the collection name as value. So I used pymongo to update existing documents with a _cls field and value equals to the collection name like this:

     db["component"].update_many({}, {"$set": {"_cls": "Component"}}, upsert=False, array_filters=None)
    

    After doing this, now I can get the documents using mongoengine Component.objects().all() query.