Mongoengine: two way referencing in mongoengine

Created on 10 Nov 2017  路  6Comments  路  Source: MongoEngine/mongoengine

Hey

i read here about two way referencing in mongoengine
https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-2
how can it be done in mongoengine?
since if i do
class A(Document): a=ReferenceField(B)
and
class B(Document): b=ReferenceField(A)
i will get error for circular imports since the module that contains A import B and the module that contains B imports A

Most helpful comment

Got it!

The problem is due to reverse_delete_rule, that breaks the deferred resolution of the reference. (register_delete_rule calls get_document)

Maybe there should be raise in the constructor to alert developers that both can't work together - or, ideally, a fix that makes it work :)

Thanks.

All 6 comments

b=ReferenceField('A') ?

awesome, thanks my bad

for some reason it does not work with CachedReferenceField
i did
a.py

class A(mongoengine.Document):
    aa = mongoengine.StringField()
    ab = mongoengine.CachedReferenceField('B', fields=['bb']

b.py

class B(mongoengine.Document):
    bb = mongoengine.StringField()
    ba = mongoengine.CachedReferenceField('A', fields=['aa']

and when i run a.py i get

mongoengine.NotRegistered: 'A' has not been registered in the document registry. Importing the document class automatically registers it, has it been imported?

@alonstern It's a bad idea to have cross-references.
Generally, a ReferenceField should be used in one way relationships pertaining to a "belongs to" relationship where consistency of data (meaning, keeping the data updated both sides) is important. If consistency is not needed, an EmbeddedDocumentField can be used.

Consider ba field on class B doesn't exist and only class A saves a reference to class B.
Then, in your case,

  1. if you need both A and B documents: query A.objects
  2. if you need only A documents: query A.objects
  3. if you need only B documents: query B.objects

I have the same issue here.
Cross-reference can be useful with Embedded documents.

class WorkSave(me.EmbeddedDocument):
   saved_at = me.DateTimeField(default=datetime.datetime.utcnow)
   work = me.LazyReferenceField('MyWork', reverse_delete_rule=me.CASCADE)

class MyWork(me.Document):
    previous_versions = me.EmbeddedDocumentListField(WorkSave)

In this case, I get mongoengine.errors.NotRegistered: MyWork has not been registered in the document registry.
I can't see any alternative (it used to work at some point though :/ )

Got it!

The problem is due to reverse_delete_rule, that breaks the deferred resolution of the reference. (register_delete_rule calls get_document)

Maybe there should be raise in the constructor to alert developers that both can't work together - or, ideally, a fix that makes it work :)

Thanks.

Was this page helpful?
0 / 5 - 0 ratings