mongoengine
mongoengine copied to clipboard
Reverse delete rule not allowed for EmbeddedDocuments
Hi!
I have the following models:
class A(Document):
name = StringField()
class Embedded(EmbeddedDocument):
ref = ReferenceField('A', reverse_delete_rule=DENY)
class B(Document):
children = MapField(EmbeddedDocumentField('Embedded'))
But I obtain the error:
File "/home/.../mongoengine/base/metaclasses.py", line 210, in __new__
raise InvalidDocumentError(msg)
mongoengine.errors.InvalidDocumentError: Reverse delete rules are not supported for EmbeddedDocuments (field: ref)
What is it due to? Is there a way to bypass this constraint?
Thanks!
Any update on this?
@Vayel have you got a workaround for this?
Is there any specific reason to use reverse_delete_rule in EmbeddedDocument? EmbeddedDocument is not saved in collection.
As the default reverse_delete_rule DO_NOTHING
for reference field. Is there a way to enable cascading on delete for EmbeddedDocument? (I do get that EmbeddedDocument not saved
in collection, but just wanna know if anything like cascading on delete could be done in EmbeddedDocuments as well.)
I would similarly like to see this available. If I have, say, multiple Comment EmbeddedDocuments contained as a list in a BlogPost Document,
class User(Document):
name = StringField()
class Comment(EmbeddedDocument):
content = StringField()
user = ReferenceField(User, reverse_delete_rule=NULLIFY)
class BlogPost(Document):
subject = StringField()
content = StringField()
comments = ListField(EmbeddedDocumentField(Comment))
The above would allow the user associated with a comment to be deleted and for all of the references on BlogPosts to be removed cleanly. As it stands at the moment (without the reverse_delete_rule) when the user gets deleted then access to BlogPost.comments[x].user raises an exception:
mongoengine.errors.DoesNotExist: Trying to dereference unknown document DBRef('user', ObjectId('...'))
Is there any workaround for this? Or does much work need to be done to allow ReferencesFields on EmbeddedDocument to support reverse_delete_rule?
Cheers.
Any news on this?
Hey, is there any update on this, or has anyone found a workaround? This is a pretty crucial feature to maintain database integrity in applications with nested document fields (which I imagine is common). Currently it seems the only option is to write a cascade rule myself, or change all of our EmbeddedDocument containing Referencefields into their own collections (I do not understand why this is necessary, is the reason technical or am I using EmbeddedDocuments improperly?)
Hello all, I came looking for a solution as well for this case and it seems no one has taken the time to change/update this behaviour.
The workaround I propose is the following; the context is using mongoengine with Flask-Admin for the CRUD handling.
Here are my models:
class Member(Document):
first_name = StringField(required=True)
last_name = StringField(required=True, unique_with='first_name')
default_role = StringField()
class ProjectRole(EmbeddedDocument):
member = ReferenceField(Member,
required=True,)
role = StringField()
class Project(Document):
members = ListField(EmbeddedDocumentField(ProjectRole, required=True))
title = StringField(unique=True, required=True)
The workaround I propose is to make a query upon deletion of a Member
that scours the Projects
in search of the projects containing the currently-being-deleted member and deleting them from those projects' ListField
of EmbeddedDocumentField
as show on the Flask-Admin view here:
class MemberView(ModelView):
def on_model_delete(self, model):
# find the projects that contain this member and delete the member from
# the ProjectRole ListField (see models for clarification)
Project.objects().update(pull__members__member=model)
The on_model_delete
function is overwritten from the Flask-Admin framework, but you should be able to handle it in the same way from a standard POST form that deletes the Member
instance.
I hope this helps. Cheers
Sad that this isn't get that much attention since 2017. This is something that is required for like chats or as eleectric mentioned for blog posts with comments. If no one is going to take on this of the maintainers or it is by design, please provide a proper solution to handle those cases. It is really unclear for me how to create a list of pre-defined dict structure without the use of embedded documents.
Tried removing the part where it throws the error (metaclasses.py) haha, but it seems it does not get the ref. We should tell MongoEngine here to respect it as an embedded document and ignore it.
File "/usr/local/lib/python3.7/site-packages/mongoengine/document.py", line 618, in delete
**self._object_key).delete(write_concern=write_concern, _from_doc_delete=True)
File "/usr/local/lib/python3.7/site-packages/mongoengine/queryset/base.py", line 467, in delete
if doc._collection == document_cls._collection:
AttributeError: type object 'ChatMember' has no attribute '_collection'
stuck on the same issue here. i would love to spend some time trying to solve it. @muuvmuuv do you still work with mongoengine ? if you do, do you know what part of the package code does the checking for the ReferenceField, I'll pretty much new to solving issues on open source content so any help would be great !
I'm new to mongoengine
an got the same issue here. I think it's important to have reverse_delete_rule
for ReferenceField
s in EmbeddedDocument
s, and most of the default rules make sense.
-
DO_NOTHING
: default behavior -
DENY
: avoid invalid reference in embedded documents -
PULL
: remove invalid references from a list in an embedded document -
NULLIFY
: nullify invalid references in an embedded document -
The only option that might not make sense is
CASCADE
, because embedded documents are not saved in collection. But one could still expect a cascaded process where the parent document of theEmbeddedDocument
is deleted from its collection.
I have the following model definitions:
class Movie(db.Document):
_id = db.SequenceField(primary_key=True)
name = db.StringField(required=True)
class Rating(db.EmbeddedDocument):
movieId = db.ReferenceField(Movie, reverse_delete_rule=db.CASCADE)
rating = db.IntField()
class User(db.Document):
_id = db.IntField(primary_key=True)
rating = db.EmbeddedDocumentListField(Rating)
Rating is a EmbeddedDocument, I want to add a reverse_delete_rule so that when a movie is deleted, a user's rating for that movie is deleted as well.
I think this is a really useful feature.
Ill second that. I dont want to switch mongo engine for something else because of this..
Still stuck on the same issue