Repository: MongoEngine/mongoengine

Issue:
Add support for $type operator.
Mongo supports a $type operator to find based on the datatype.  Mongoengine doesn't allow type__ as an operator, though.  I monkeypatched it with this, but obviously it should just be added.  

```
from  mongoengine.queryset import transform
# This is the original with type appended.
COMPARISON_OPERATORS = ('ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod',
                'all', 'size', 'exists', 'not', 'type')   

# These are all exactly from transform.py
GEO_OPERATORS        = ('within_distance', 'within_spherical_distance',
                        'within_box', 'within_polygon', 'near', 'near_sphere',
                        'max_distance', 'geo_within', 'geo_within_box',
                        'geo_within_polygon', 'geo_within_center',
                        'geo_within_sphere', 'geo_intersects')
STRING_OPERATORS     = ('contains', 'icontains', 'startswith',
                        'istartswith', 'endswith', 'iendswith',
                        'exact', 'iexact')
CUSTOM_OPERATORS     = ('match',)
MATCH_OPERATORS      = (COMPARISON_OPERATORS + GEO_OPERATORS +
                        STRING_OPERATORS + CUSTOM_OPERATORS)

# This is to monkeypatch it in.
transform.COMPARISON_OPERATORS = COMPARISON_OPERATORS
transform.MATCH_OPERATORS = MATCH_OPERATORS
```

Add support for $type operator.
Mongo supports a $type operator to find based on the datatype.  Mongoengine doesn't allow type__ as an operator, though.  I monkeypatched it with this, but obviously it should just be added.  

```
from  mongoengine.queryset import transform
# This is the original with type appended.
COMPARISON_OPERATORS = ('ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod',
                'all', 'size', 'exists', 'not', 'type')   

# These are all exactly from transform.py
GEO_OPERATORS        = ('within_distance', 'within_spherical_distance',
                        'within_box', 'within_polygon', 'near', 'near_sphere',
                        'max_distance', 'geo_within', 'geo_within_box',
                        'geo_within_polygon', 'geo_within_center',
                        'geo_within_sphere', 'geo_intersects')
STRING_OPERATORS     = ('contains', 'icontains', 'startswith',
                        'istartswith', 'endswith', 'iendswith',
                        'exact', 'iexact')
CUSTOM_OPERATORS     = ('match',)
MATCH_OPERATORS      = (COMPARISON_OPERATORS + GEO_OPERATORS +
                        STRING_OPERATORS + CUSTOM_OPERATORS)

# This is to monkeypatch it in.
transform.COMPARISON_OPERATORS = COMPARISON_OPERATORS
transform.MATCH_OPERATORS = MATCH_OPERATORS
```



Discussion:

Resolving patch:
diff --git a/mongoengine/queryset/transform.py b/mongoengine/queryset/transform.py
--- a/mongoengine/queryset/transform.py
+++ b/mongoengine/queryset/transform.py
@@ -11,7 +11,7 @@
 
 
 COMPARISON_OPERATORS = ('ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod',
-                        'all', 'size', 'exists', 'not', 'elemMatch')
+                        'all', 'size', 'exists', 'not', 'elemMatch', 'type')
 GEO_OPERATORS = ('within_distance', 'within_spherical_distance',
                  'within_box', 'within_polygon', 'near', 'near_sphere',
                  'max_distance', 'geo_within', 'geo_within_box',


Test patch:
diff --git a/tests/queryset/transform.py b/tests/queryset/transform.py
--- a/tests/queryset/transform.py
+++ b/tests/queryset/transform.py
@@ -197,5 +197,17 @@ class Location(Document):
         update = transform.update(Location, set__poly={"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]})
         self.assertEqual(update, {'$set': {'poly': {"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]}}})
 
+    def test_type(self):
+        class Doc(Document):
+            df = DynamicField()
+        Doc(df=True).save()
+        Doc(df=7).save()
+        Doc(df="df").save()
+        self.assertEqual(Doc.objects(df__type=1).count(), 0)  # double
+        self.assertEqual(Doc.objects(df__type=8).count(), 1)  # bool
+        self.assertEqual(Doc.objects(df__type=2).count(), 1)  # str
+        self.assertEqual(Doc.objects(df__type=16).count(), 1)  # int
+
+
 if __name__ == '__main__':
     unittest.main()