diff --git a/docs/guide/defining-documents.rst b/docs/guide/defining-documents.rst index 6b9fcdd9..a7d48f7c 100644 --- a/docs/guide/defining-documents.rst +++ b/docs/guide/defining-documents.rst @@ -431,10 +431,25 @@ If a dictionary is passed then the following options are available: :attr:`unique` (Default: False) Whether the index should be sparse. -.. note:: - Geospatial indexes will be automatically created for all - :class:`~mongoengine.GeoPointField`\ s +Geospatial indexes +--------------------------- +Geospatial indexes will be automatically created for all +:class:`~mongoengine.GeoPointField`\ s + +It is also possible to explicitly define geospatial indexes. This is +useful if you need to define a geospatial index on a subfield of a +:class:`~mongoengine.DictField` or a custom field that contains a +point. To create a geospatial index you must prefix the field with the +***** sign. :: + + class Place(Document): + location = DictField() + meta = { + 'indexes': [ + '*location.point', + ], + } Ordering ======== diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 9032fc7f..64b29fff 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -399,12 +399,14 @@ class QuerySet(object): index_list = [] use_types = doc_cls._meta.get('allow_inheritance', True) for key in spec['fields']: - # Get direction from + or - + # Get ASCENDING direction from +, DESCENDING from -, and GEO2D from * direction = pymongo.ASCENDING if key.startswith("-"): direction = pymongo.DESCENDING - if key.startswith(("+", "-")): - key = key[1:] + elif key.startswith("*"): + direction = pymongo.GEO2D + if key.startswith(("+", "-", "*")): + key = key[1:] # Use real field name, do it manually because we need field # objects for the next part (list field checking) @@ -421,7 +423,7 @@ class QuerySet(object): # If _types is being used, prepend it to every specified index index_types = doc_cls._meta.get('index_types', True) allow_inheritance = doc_cls._meta.get('allow_inheritance') - if spec.get('types', index_types) and allow_inheritance and use_types: + if spec.get('types', index_types) and allow_inheritance and use_types and direction is not pymongo.GEO2D: index_list.insert(0, ('_types', 1)) spec['fields'] = index_list diff --git a/tests/document.py b/tests/document.py index b06731dd..fc9350b3 100644 --- a/tests/document.py +++ b/tests/document.py @@ -633,6 +633,26 @@ class DocumentTest(unittest.TestCase): BlogPost.drop_collection() + def test_explicit_geo2d_index(self): + """Ensure that geo2d indexes work when created via meta[indexes] + """ + class Place(Document): + location = DictField() + meta = { + 'indexes': [ + '*location.point', + ], + } + Place.drop_collection() + + info = Place.objects._collection.index_information() + # Indexes are lazy so use list() to perform query + list(Place.objects) + info = Place.objects._collection.index_information() + info = [value['key'] for key, value in info.iteritems()] + + self.assertTrue([('location.point', '2d')] in info) + def test_dictionary_indexes(self): """Ensure that indexes are used when meta[indexes] contains dictionaries instead of lists.