diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index a477e370..69c78b28 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -476,22 +476,39 @@ class QuerySet(object): index_opts = self._document._meta.get('index_options', {}) index_types = self._document._meta.get('index_types', True) + # determine if an index which we are creating includes + # _type as its first field; if so, we can avoid creating + # an extra index on _type, as mongodb will use the existing + # index to service queries against _type + types_indexed = False + def includes_types(fields): + first_field = None + if len(fields): + if isinstance(fields[0], basestring): + first_field = fields[0] + elif isinstance(fields[0], (list, tuple)) and len(fields[0]): + first_field = fields[0][0] + return first_field == '_types' + # Ensure indexes created by uniqueness constraints for index in self._document._meta['unique_indexes']: + types_indexed = types_indexed or includes_types(index) self._collection.ensure_index(index, unique=True, background=background, drop_dups=drop_dups, **index_opts) # Ensure document-defined indexes are created if self._document._meta['indexes']: for spec in self._document._meta['indexes']: + types_indexed = types_indexed or includes_types(spec['fields']) opts = index_opts.copy() opts['unique'] = spec.get('unique', False) opts['sparse'] = spec.get('sparse', False) self._collection.ensure_index(spec['fields'], background=background, **opts) - # If _types is being used (for polymorphism), it needs an index - if index_types and '_types' in self._query: + # If _types is being used (for polymorphism), it needs an index, + # only if another index doesn't begin with _types + if index_types and '_types' in self._query and not types_indexed: self._collection.ensure_index('_types', background=background, **index_opts) diff --git a/tests/document.py b/tests/document.py index 9498cfb2..0c056a16 100644 --- a/tests/document.py +++ b/tests/document.py @@ -397,7 +397,7 @@ class DocumentTest(unittest.TestCase): info = collection.index_information() info = [value['key'] for key, value in info.iteritems()] - self.assertEquals([[(u'_id', 1)], [(u'_types', 1)], [(u'_types', 1), (u'name', 1)]], info) + self.assertEquals([[(u'_id', 1)], [(u'_types', 1), (u'name', 1)]], info) # Turn off inheritance class Animal(Document): @@ -415,7 +415,7 @@ class DocumentTest(unittest.TestCase): info = collection.index_information() info = [value['key'] for key, value in info.iteritems()] - self.assertEquals([[(u'_id', 1)], [(u'_types', 1)], [(u'_types', 1), (u'name', 1)]], info) + self.assertEquals([[(u'_id', 1)], [(u'_types', 1), (u'name', 1)]], info) info = collection.index_information() indexes_to_drop = [key for key, value in info.iteritems() if '_types' in dict(value['key'])] @@ -601,8 +601,11 @@ class DocumentTest(unittest.TestCase): BlogPost.drop_collection() info = BlogPost.objects._collection.index_information() - # _id, types, '-date', 'tags', ('cat', 'date') - self.assertEqual(len(info), 5) + # _id, '-date', 'tags', ('cat', 'date') + # NB: there is no index on _types by itself, since + # the indices on -date and tags will both contain + # _types as first element in the key + self.assertEqual(len(info), 4) # Indexes are lazy so use list() to perform query list(BlogPost.objects)