MongoEngine / MongoEngine/mongoengine

`unique` fails if `db_field` is set on an EmbeddedDocument

Open
#1,225 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug
Dominant language
Python
Stars
4.3k
Forks
1.2k
Avg merge
4h 41m
Merged PRs (30d)
11

Description

I have been running into various problems when combining db_field=True with pretty much any other MongoEngine features. Today I tried to set unique=True on a string field, only to find out the database would raise a NotUniqueError for any more than a single document per collection.

Here is my example schema:

class Name(EmbeddedDocument):
    _first = StringField(db_field='first')
    _middle = StringField(db_field='middle')
    _last = StringField(db_field='last', required=True)
    _full = StringField(db_field='full', required=True, unique=True)

    @property
    def first(self):
        return self._first

    # (...)


class Person(Document):
    _name = EmbeddedDocumentField(Name, db_field='name',
                                  required=True, default=Name)
    _desc = StringField(db_field='desc')
    _birth = EmbeddedDocumentField(Year, db_field='birth')
    _death = EmbeddedDocumentField(Year, db_field='death')

    @property
    def name(self):
        return self._name

    # (...)

If I created a person with the full name "John Doe", that would work fine. Creating a second person with the name "Jimmy Bob" (or any other name), however, raises a NotUniqueError.

Looking at the indexes in MongoDB:

> db.person.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "citeline_dev.person"
    },
    {
    "v" : 1,
        "unique" : true,
        "key" : {
            "_name.full" : 1
        },
        "name" : "_name.full_1",
        "ns" : "citeline_dev.person",
        "sparse" : false,
        "background" : false
    }
]

With that I gathered the field was setting the index name based on the attribute Person._name, which does not match the db_field setting of name.

To work around this issue I modified Person to use a global index:

class Person(Document):
    # (...)
    meta = {
        'indexes': [
            {
                'fields': ['_name._full'],
                'unique': True
            }
        ]
    }
    # (...)

Note: At first I tried to set the fields to name.full, however, MongoEngine complained that neither name nor field were set.

Please consider fixing the field options so they work out of the box with the db_field option.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source file or test is named in the issue. Start by reproducing the EmbeddedDocument schema and inspecting the generated MongoDB index; done means a unique field using db_field creates the index on the stored field path and permits distinct values in separate documents.

Written by the indexing model from the issue text.

Assessment

Tech stack
mongodb, python
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.