Julien Ribon
Julien Ribon

Reputation: 275

mongokit index does not work

I am developing a Web application using Flask and MongoDB. And I use (Flask-)MongoKit to define a schema to validate my data.

In my database, there is a collection called "users" (see below) that contains a field "email". I try to create a unique index on that field as specified in the MongoKit documentation (http://namlook.github.com/mongokit/indexes.html). However, when I check the collection indexes via MongoDB client shell, there is no index "email" at all.

I found a similar issue on the net: "unique index does not work" (https://github.com/namlook/mongokit/issues/98)

Does someone has any idea why it does not work?

User collection:

@db.register
class User(Model):

    __collection__ = 'users'

    structure = {
        'first_name': basestring,
        'last_name': basestring,
        'email': basestring,
        'password': unicode,
        'registration_date': datetime,
    }

    required_fields = ['first_name', 'last_name', 'email', 'password', 'registration_date']

    default_values = {
        'registration_date': datetime.utcnow,
    }

    # Create a unique index on the "email" field
    indexes = [
        {
            'fields': 'email',  # note: this may be an array
            'unique': True,     # only unique values are allowed 
            'ttl': 0,           # create index immediately
        },
    ]

db.users.getIndexes() output:

[
{
    "v" : 1,
    "key" : {
        "_id" : 1
    },
    "ns" : "youthmind.users",
    "name" : "_id_"
},
]

Note that I also try without 'ttl':0, and I was able to create an index using the following piece of code:

db.users.create_index('email', unique=True)

I think this uses the pymongo Connection object directly.

Thanks in advance for your help.

Upvotes: 4

Views: 937

Answers (3)

harry
harry

Reputation: 1081

I use Flask-Script so it was easy to add Marboni's answer as a command to my manage script which is easy to run.

@manager.command
def setup_indexes():
    """
    create index for all the registered_documents
    """
    for doc in application.db.registered_documents:
        collection = application.db[doc.__collection__]
        doc.generate_index(collection)

I keep my database as member of app (application.db) for various admin stuff. Now whenever I add few index or change anything I run my manager command.

./manage.py setup_indexes

You can read more about manager module here http://flask-script.readthedocs.org/en/latest/

Upvotes: 0

Marboni
Marboni

Reputation: 2459

Right, you need to use separate script to recreate DB with indexes. It will be called if needed, not each time server runs. Example:

def recreatedb(uri, database_name):
    connection = Connection(uri)
    connection.drop_database(database_name)
    #noinspection PyStatementEffect
    connection[database_name]
    connection.register(_DOCUMENTS)
    for document_name, obj in connection._registered_documents.iteritems():
        obj.generate_index(connection[database_name][obj._obj_class.__collection__])

To prevent using database without indexes:

def init_engine(uri, database_name):
    global db
    connection = Connection(uri)
    if database_name not in connection.database_names():
        recreatedb(uri, database_name)
    connection.register(_DOCUMENTS)
    db = connection[database_name]

Upvotes: 3

Christopher Currens
Christopher Currens

Reputation: 30695

You are doing it exactly how you should be doing it. Automatic index creation has been removed from MongoKit as of version 0.7.1 (maybe version 0.8?). Here is an issue for it.

The reason behind it is that the it would have to call ensureIndex on the collection. The "ensure" part of the name makes it seem like it would check and then create the index if it doesn't exist, but a developer from Mongo said that it might still wind up (re-)creating the entire index, which could be terribly expensive. The developer also said it should be considered an administrative task, instead of a development task.

The work around is to call create_index yourself on for each index in the list you've defined as part of an upgrade/create script.

Upvotes: 4

Related Questions