Mongoengine: Why duplication field error is raised with a description without referring to the field in machine readable code way?

Created on 6 Oct 2017  路  4Comments  路  Source: MongoEngine/mongoengine

I have multiple unique keys in a collection, and when there is a duplication and NotUniqueError exception is raised I could not understand which field is a duplicated field.

The example error response:
Tried to save duplicate unique keys (E11000 duplicate key error collection: my_db.user index: username_1 dup key: { : "sample_username" })'}}

Isn't there a way to say exactly which field is duplicated? The problem is that when I want to return error to API gateway, I cannot say which field is duplicated?

Is there a workaround for this? Or any plan to fix this issue?

Most helpful comment

Unique constraint will create an index in background. Error message says index username_1 has got duplicate error with sample_username value. Correct me if I am wrong! I think we don't need to complicate things that much

All 4 comments

Unique constraint will create an index in background. Error message says index username_1 has got duplicate error with sample_username value. Correct me if I am wrong! I think we don't need to complicate things that much

That would be helpful if we could have an extra field (property) on Base exception class and get the desired duplicated key.

This error is fired from pymongo, it seems fair to avoid hacking into it. Doing this in mongoengine would require parsing the message, extract the index name and cross the information with the Document indexes. There could be edge cases depending on the index type and there could be dependency to the version of pymongo & mongodb so it sounds a bit fragile.

By parsing the message, you should be able to collect the field name from the index name. I see 2 workarounds, that aren't perfect but that should do the trick:

Considering the following class:

class User(me.Document):
    name = me.StringField(unique=True)
    email = me.StringField(unique=True)
  • Run a query before inserting to see if there is any match with what you are inserting
    User.objects(me.Q(name='Doe') | me.Q(email='[email protected]'))
  • Parse the exception message with something like this:
try:
    User(name='Foo', email='[email protected]').save()
except me.errors.NotUniqueError as exc:
    for field in unique_fields:    # You could also loop in User._fields to make something generic
        if field in str(exc):
            raise Exception('field {} is not unique'.format(field))

Its not bulletproof but it does the trick for simple cases.

I think we can close this unless you want to do something about it @erdenezul ?

Was this page helpful?
0 / 5 - 0 ratings