Search code examples
pythonflaskmongoengineflask-mongoengine

MongoEngine recursive embedding


I am trying to model a document with mongoengine but I can't figure out how I can do recursive embedding. For example I want to do something like this

class NavigationHelper(EmbeddedDocument):
    name = StringField()
    url = URLField()
    sub_menus = EmbeddedDocumentListField(NavigationHelper)

I will use this to create a navigation tree with infinite sub-menu possibility. for example

-menu-1

--sub-menu-1-1

---sub-menu-1-1-1

---sub-menu-1-1-2

----sub-menu-1-1-2-1

-menu-2

is there any way for to model this? Thanks a lot.


Solution

  • You can model that with one high level Document and a list of EmbeddedDocument.

    from mongoengine import Document, EmbeddedDocument, StringField, URLField, EmbeddedDocumentListField
    
    # The embeddedDocument of sub-menus
    class NavigationSubMenu(EmbeddedDocument):
        name = StringField()
        url = URLField()
        sub_menus = EmbeddedDocumentListField('NavigationSubMenu')
    
    
    # The document for the main menus
    class NavigationMenu(Document):
        name = StringField()
        url = URLField()
        sub_menus = EmbeddedDocumentListField(NavigationSubMenu)
    

    The example you gave would be created by:

    docs = [
        NavigationMenu(name='1',
                       sub_menus=[
                           NavigationSubMenu(name='1-1',
                                             sub_menus=[
                                                 NavigationSubMenu(name='1-1-1'),
                                                 NavigationSubMenu(name='1-1-2',
                                                                   sub_menus=[
                                                                       NavigationSubMenu(name='1-1-2-1')
                                                                   ])
                                             ])
                       ]
                       ),
        NavigationMenu(name='2')
    ]
    
    for doc in docs:
        doc.save()
    
    docs = NavigationMenu.objects()
    
    for doc in docs:
        print(doc.name)
        while len(doc.sub_menus) > 0:
            for sub_menu in doc.sub_menus:
                print(sub_menu.name)
                doc = sub_menu
    
    >> 1
    >> 1-1
    >> 1-1-1
    >> 1-1-2
    >> 1-1-2-1
    >> 2
    

    If you save this, you will get 2 documents. One for each high level NavigationMenu.