Search code examples
pythonmongodbpython-3.xinheritancemongoengine

How to query MongoEngine documents with inheritance?


I've been using a Node MongoEngine document for a while.

I am trying to go from a simpe Node model to some more specific elements inheriting from it.

What I've done so far

At first, I was not aware of the inheritance possibility offered by MongoEngine (see here), so I was using a 'label' field to distinguish between 3 types of Nodes (respectively Keyword, Url and Domain).

Here is the original model:

class Node(Document):
    project = ReferenceField(Project,
                             reverse_delete_rule=CASCADE,
                             required=True,)
    name = StringField(required=True, unique_with=['project', 'label'])
    label = StringField(required=True)
    volume = IntField()
    clusters = ListField(ReferenceField(Cluster, reverse_delete_rule=PULL))
    x = FloatField(default=random.random())
    y = FloatField(default=random.random())
    connections = IntField(default=0)
    meta = {
        'indexes': ['project', 'label', 'name', 'clusters'],
    }

I worked for some time with this model, so the node collection is currently populated with thousands of documents.

Then I implemented inheritance by adding 'allow_inheritance': True to the model and creating the following model:

Inherited model

class Keyword(Node):
    """ A MongoEngine Document for keyword management. """
    a_keywor_specific field = IntField()

    def foo(self):
        print('this is a keyword specific method')

Now this works fine for creating and saving new Keyword documents.

The thing I'm having trouble with is querying the old Nodes added before this change.

Question

If I try to query all the existing nodes, only the one I added after the inheritance change is returned:

In [21]: Node.objects()
Out[21]: [<Keyword: Keyword object>]
  • How can I access all the Nodes that were added before introducing inheritance ?
  • Is there any way to migrate those old Nodes to Keywords, Urls and Domains based on their original label attribute ?

Thanks !


Solution

  • This happened because when you created an inherited model, the old model queries use _cls attribute to query this model's documents. But old documents don't have this field.

    Fill in this attribute for old documents.

    Regarding your second question.

    I think, if you are going to make a migration script that will fill _cls field, you can fill its value depending on the value of label field.

    You can find the required _cls values inserting documents for each model.