We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
"'float' object is not iterable" when using coordinates for MongoDB query
I'm trying to run a query using **MongoDB** and the **[$geoNear](http://docs.mongodb.org/manual/reference/operator/aggregation/geoNear/)** function, but every time I type the origin coordinate using floats (to create a [GeoJSON Point](http://docs.mongodb.org/manual/reference/geojson/)), I get an error: [_from Python?_]

 `Error running query: 'float' object is not iterable`

I'm trying to run the query below. The problem here is the `[ -22.910079, -43.205161 ]` part.

``` json
{
  "collection": "bus",
  "aggregate": [
    { 
        "$geoNear": { 
            "near": { "type": "Point", "coordinates": [ -22.910079, -43.205161 ] },
            "maxDistance": 100000000,
            "distanceField": "dist.calculated",
            "includeLocs": "dist.location",
            "spherical": true
        }
    }    
  ]
}
```

However, if I use the coordinates with integers, such as `[ -22, -43 ]`, the query runs fine, but this coordinate is now meaningless, obviously. Here is an example that doesn't error:

``` json
{
  "collection": "bus",
  "aggregate": [
    { 
        "$geoNear": { 
            "near": { "type": "Point", "coordinates": [ -22, -43 ] },
            "maxDistance": 100000000,
            "distanceField": "dist.calculated",
            "includeLocs": "dist.location",
            "spherical": true
        }
    }    
  ]
}
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `redash/query_runner/mongodb.py`
Content:
```
1 import json
2 import datetime
3 import logging
4 import re
5 from dateutil.parser import parse
6 
7 from redash.utils import JSONEncoder
8 from redash.query_runner import *
9 
10 logger = logging.getLogger(__name__)
11 
12 try:
13     import pymongo
14     from bson.objectid import ObjectId
15     from bson.son import SON
16     enabled = True
17 
18 except ImportError:
19     enabled = False
20 
21 
22 TYPES_MAP = {
23     str: TYPE_STRING,
24     unicode: TYPE_STRING,
25     int: TYPE_INTEGER,
26     long: TYPE_INTEGER,
27     float: TYPE_FLOAT,
28     bool: TYPE_BOOLEAN,
29     datetime.datetime: TYPE_DATETIME,
30 }
31 
32 date_regex = re.compile("ISODate\(\"(.*)\"\)", re.IGNORECASE)
33 
34 class MongoDBJSONEncoder(JSONEncoder):
35     def default(self, o):
36         if isinstance(o, ObjectId):
37             return str(o)
38 
39         return super(MongoDBJSONEncoder, self).default(o)
40 
41 # Simple query example:
42 #
43 # {
44 #     "collection" : "my_collection",
45 #     "query" : {
46 #         "date" : {
47 #             "$gt" : "ISODate(\"2015-01-15 11:41\")",
48 #         },
49 #         "type" : 1
50 #     },
51 #     "fields" : {
52 #         "_id" : 1,
53 #         "name" : 2
54 #     },
55 #     "sort" : [
56 #        {
57 #             "name" : "date",
58 #             "direction" : -1
59 #        }
60 #     ]
61 #
62 # }
63 #
64 #
65 # Aggregation
66 # ===========
67 # Uses a syntax similar to the one used in PyMongo, however to support the
68 # correct order of sorting, it uses a regular list for the "$sort" operation
69 # that converts into a SON (sorted dictionary) object before execution.
70 #
71 # Aggregation query example:
72 #
73 # {
74 #     "collection" : "things",
75 #     "aggregate" : [
76 #         {
77 #             "$unwind" : "$tags"
78 #         },
79 #         {
80 #             "$group" : {
81 #                 "_id" : "$tags",
82 #                 "count" : { "$sum" : 1 }
83 #             }
84 #         },
85 #         {
86 #             "$sort" : [
87 #                 {
88 #                     "name" : "count",
89 #                     "direction" : -1
90 #                 },
91 #                 {
92 #                     "name" : "_id",
93 #                     "direction" : -1
94 #                 }
95 #             ]
96 #         }
97 #     ]
98 # }
99 #
100 #
101 class MongoDB(BaseQueryRunner):
102     @classmethod
103     def configuration_schema(cls):
104         return {
105             'type': 'object',
106             'properties': {
107                 'connectionString': {
108                     'type': 'string',
109                     'title': 'Connection String'
110                 },
111                 'dbName': {
112                     'type': 'string',
113                     'title': "Database Name"
114                 },
115                 'replicaSetName': {
116                     'type': 'string',
117                     'title': 'Replica Set Name'
118                 },
119             },
120             'required': ['connectionString']
121         }
122 
123     @classmethod
124     def enabled(cls):
125         return enabled
126 
127     @classmethod
128     def annotate_query(cls):
129         return False
130 
131     def __init__(self, configuration_json):
132         super(MongoDB, self).__init__(configuration_json)
133 
134         self.syntax = 'json'
135 
136         self.db_name = self.configuration["dbName"]
137 
138         self.is_replica_set = True if "replicaSetName" in self.configuration and self.configuration["replicaSetName"] else False
139 
140     def _get_column_by_name(self, columns, column_name):
141         for c in columns:
142             if "name" in c and c["name"] == column_name:
143                 return c
144 
145         return None
146 
147     def _fix_dates(self, data):
148         for k in data:
149             if isinstance(data[k], list):
150                 for i in range(0, len(data[k])):
151                     if isinstance(data[k][i], (str, unicode)):
152                         self._convert_date(data[k], i)
153                     elif not isinstance(data[k][i], (int)):
154                         self._fix_dates(data[k][i])
155 
156             elif isinstance(data[k], dict):
157                 self._fix_dates(data[k])
158             else:
159                 if isinstance(data[k], (str, unicode)):
160                     self._convert_date(data, k)
161 
162     def _convert_date(self, q, field_name):
163         m = date_regex.findall(q[field_name])
164         if len(m) > 0:
165             q[field_name] = parse(m[0], yearfirst=True)
166 
167     def run_query(self, query):
168         if self.is_replica_set:
169             db_connection = pymongo.MongoReplicaSetClient(self.configuration["connectionString"], replicaSet=self.configuration["replicaSetName"])
170         else:
171             db_connection = pymongo.MongoClient(self.configuration["connectionString"])
172 
173         db = db_connection[self.db_name]
174 
175         logger.debug("mongodb connection string: %s", self.configuration['connectionString'])
176         logger.debug("mongodb got query: %s", query)
177 
178         try:
179             query_data = json.loads(query)
180             self._fix_dates(query_data)
181         except ValueError:
182             return None, "Invalid query format. The query is not a valid JSON."
183 
184         if "collection" not in query_data:
185             return None, "'collection' must have a value to run a query"
186         else:
187             collection = query_data["collection"]
188 
189         q = query_data.get("query", None)
190         f = None
191 
192         aggregate = query_data.get("aggregate", None)
193         if aggregate:
194             for step in aggregate:
195                 if "$sort" in step:
196                     sort_list = []
197                     for sort_item in step["$sort"]:
198                         sort_list.append((sort_item["name"], sort_item["direction"]))
199 
200                     step["$sort"] = SON(sort_list)
201 
202         if not aggregate:
203             s = None
204             if "sort" in query_data and query_data["sort"]:
205                 s = []
206                 for field in query_data["sort"]:
207                     s.append((field["name"], field["direction"]))
208 
209         if "fields" in query_data:
210             f = query_data["fields"]
211 
212         s = None
213         if "sort" in query_data and query_data["sort"]:
214             s = []
215             for field_data in query_data["sort"]:
216                 s.append((field_data["name"], field_data["direction"]))
217 
218         columns = []
219         rows = []
220 
221         cursor = None
222         if q or (not q and not aggregate):
223             if s:
224                 cursor = db[collection].find(q, f).sort(s)
225             else:
226                 cursor = db[collection].find(q, f)
227 
228             if "skip" in query_data:
229                 cursor = cursor.skip(query_data["skip"])
230 
231             if "limit" in query_data:
232                 cursor = cursor.limit(query_data["limit"])
233 
234         elif aggregate:
235             r = db[collection].aggregate(aggregate)
236 
237             # Backwards compatibility with older pymongo versions.
238             #
239             # Older pymongo version would return a dictionary from an aggregate command.
240             # The dict would contain a "result" key which would hold the cursor.
241             # Newer ones return pymongo.command_cursor.CommandCursor.
242             if isinstance(r, dict):
243                 cursor = r["result"]
244             else:
245                 cursor = r
246 
247         for r in cursor:
248             for k in r:
249                 if self._get_column_by_name(columns, k) is None:
250                     columns.append({
251                         "name": k,
252                         "friendly_name": k,
253                         "type": TYPES_MAP.get(type(r[k]), TYPE_STRING)
254                     })
255 
256             rows.append(r)
257 
258         if f:
259             ordered_columns = []
260             for k in sorted(f, key=f.get):
261                 ordered_columns.append(self._get_column_by_name(columns, k))
262 
263             columns = ordered_columns
264 
265         data = {
266             "columns": columns,
267             "rows": rows
268         }
269         error = None
270         json_data = json.dumps(data, cls=MongoDBJSONEncoder)
271 
272         return json_data, error
273 
274 register(MongoDB)
275
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/redash/query_runner/mongodb.py b/redash/query_runner/mongodb.py
--- a/redash/query_runner/mongodb.py
+++ b/redash/query_runner/mongodb.py
@@ -29,7 +29,6 @@
     datetime.datetime: TYPE_DATETIME,
 }
 
-date_regex = re.compile("ISODate\(\"(.*)\"\)", re.IGNORECASE)
 
 class MongoDBJSONEncoder(JSONEncoder):
     def default(self, o):
@@ -38,66 +37,25 @@
 
         return super(MongoDBJSONEncoder, self).default(o)
 
-# Simple query example:
-#
-# {
-#     "collection" : "my_collection",
-#     "query" : {
-#         "date" : {
-#             "$gt" : "ISODate(\"2015-01-15 11:41\")",
-#         },
-#         "type" : 1
-#     },
-#     "fields" : {
-#         "_id" : 1,
-#         "name" : 2
-#     },
-#     "sort" : [
-#        {
-#             "name" : "date",
-#             "direction" : -1
-#        }
-#     ]
-#
-# }
-#
-#
-# Aggregation
-# ===========
-# Uses a syntax similar to the one used in PyMongo, however to support the
-# correct order of sorting, it uses a regular list for the "$sort" operation
-# that converts into a SON (sorted dictionary) object before execution.
-#
-# Aggregation query example:
-#
-# {
-#     "collection" : "things",
-#     "aggregate" : [
-#         {
-#             "$unwind" : "$tags"
-#         },
-#         {
-#             "$group" : {
-#                 "_id" : "$tags",
-#                 "count" : { "$sum" : 1 }
-#             }
-#         },
-#         {
-#             "$sort" : [
-#                 {
-#                     "name" : "count",
-#                     "direction" : -1
-#                 },
-#                 {
-#                     "name" : "_id",
-#                     "direction" : -1
-#                 }
-#             ]
-#         }
-#     ]
-# }
-#
-#
+
+date_regex = re.compile("ISODate\(\"(.*)\"\)", re.IGNORECASE)
+
+
+def datetime_parser(dct):
+    for k, v in dct.iteritems():
+        if isinstance(v, basestring):
+            m = date_regex.findall(v)
+            if len(m) > 0:
+                dct[k] = parse(m[0], yearfirst=True)
+
+    return dct
+
+
+def parse_query_json(query):
+    query_data = json.loads(query, object_hook=datetime_parser)
+    return query_data
+
+
 class MongoDB(BaseQueryRunner):
     @classmethod
     def configuration_schema(cls):
@@ -144,25 +102,6 @@
 
         return None
 
-    def _fix_dates(self, data):
-        for k in data:
-            if isinstance(data[k], list):
-                for i in range(0, len(data[k])):
-                    if isinstance(data[k][i], (str, unicode)):
-                        self._convert_date(data[k], i)
-                    elif not isinstance(data[k][i], (int)):
-                        self._fix_dates(data[k][i])
-
-            elif isinstance(data[k], dict):
-                self._fix_dates(data[k])
-            else:
-                if isinstance(data[k], (str, unicode)):
-                    self._convert_date(data, k)
-
-    def _convert_date(self, q, field_name):
-        m = date_regex.findall(q[field_name])
-        if len(m) > 0:
-            q[field_name] = parse(m[0], yearfirst=True)
 
     def run_query(self, query):
         if self.is_replica_set:
@@ -176,8 +115,7 @@
         logger.debug("mongodb got query: %s", query)
 
         try:
-            query_data = json.loads(query)
-            self._fix_dates(query_data)
+            query_data = parse_query_json(query)
         except ValueError:
             return None, "Invalid query format. The query is not a valid JSON."

{"golden_diff": "diff --git a/redash/query_runner/mongodb.py b/redash/query_runner/mongodb.py\n--- a/redash/query_runner/mongodb.py\n+++ b/redash/query_runner/mongodb.py\n@@ -29,7 +29,6 @@\n     datetime.datetime: TYPE_DATETIME,\n }\n \n-date_regex = re.compile(\"ISODate\\(\\\"(.*)\\\"\\)\", re.IGNORECASE)\n \n class MongoDBJSONEncoder(JSONEncoder):\n     def default(self, o):\n@@ -38,66 +37,25 @@\n \n         return super(MongoDBJSONEncoder, self).default(o)\n \n-# Simple query example:\n-#\n-# {\n-#     \"collection\" : \"my_collection\",\n-#     \"query\" : {\n-#         \"date\" : {\n-#             \"$gt\" : \"ISODate(\\\"2015-01-15 11:41\\\")\",\n-#         },\n-#         \"type\" : 1\n-#     },\n-#     \"fields\" : {\n-#         \"_id\" : 1,\n-#         \"name\" : 2\n-#     },\n-#     \"sort\" : [\n-#        {\n-#             \"name\" : \"date\",\n-#             \"direction\" : -1\n-#        }\n-#     ]\n-#\n-# }\n-#\n-#\n-# Aggregation\n-# ===========\n-# Uses a syntax similar to the one used in PyMongo, however to support the\n-# correct order of sorting, it uses a regular list for the \"$sort\" operation\n-# that converts into a SON (sorted dictionary) object before execution.\n-#\n-# Aggregation query example:\n-#\n-# {\n-#     \"collection\" : \"things\",\n-#     \"aggregate\" : [\n-#         {\n-#             \"$unwind\" : \"$tags\"\n-#         },\n-#         {\n-#             \"$group\" : {\n-#                 \"_id\" : \"$tags\",\n-#                 \"count\" : { \"$sum\" : 1 }\n-#             }\n-#         },\n-#         {\n-#             \"$sort\" : [\n-#                 {\n-#                     \"name\" : \"count\",\n-#                     \"direction\" : -1\n-#                 },\n-#                 {\n-#                     \"name\" : \"_id\",\n-#                     \"direction\" : -1\n-#                 }\n-#             ]\n-#         }\n-#     ]\n-# }\n-#\n-#\n+\n+date_regex = re.compile(\"ISODate\\(\\\"(.*)\\\"\\)\", re.IGNORECASE)\n+\n+\n+def datetime_parser(dct):\n+    for k, v in dct.iteritems():\n+        if isinstance(v, basestring):\n+            m = date_regex.findall(v)\n+            if len(m) > 0:\n+                dct[k] = parse(m[0], yearfirst=True)\n+\n+    return dct\n+\n+\n+def parse_query_json(query):\n+    query_data = json.loads(query, object_hook=datetime_parser)\n+    return query_data\n+\n+\n class MongoDB(BaseQueryRunner):\n     @classmethod\n     def configuration_schema(cls):\n@@ -144,25 +102,6 @@\n \n         return None\n \n-    def _fix_dates(self, data):\n-        for k in data:\n-            if isinstance(data[k], list):\n-                for i in range(0, len(data[k])):\n-                    if isinstance(data[k][i], (str, unicode)):\n-                        self._convert_date(data[k], i)\n-                    elif not isinstance(data[k][i], (int)):\n-                        self._fix_dates(data[k][i])\n-\n-            elif isinstance(data[k], dict):\n-                self._fix_dates(data[k])\n-            else:\n-                if isinstance(data[k], (str, unicode)):\n-                    self._convert_date(data, k)\n-\n-    def _convert_date(self, q, field_name):\n-        m = date_regex.findall(q[field_name])\n-        if len(m) > 0:\n-            q[field_name] = parse(m[0], yearfirst=True)\n \n     def run_query(self, query):\n         if self.is_replica_set:\n@@ -176,8 +115,7 @@\n         logger.debug(\"mongodb got query: %s\", query)\n \n         try:\n-            query_data = json.loads(query)\n-            self._fix_dates(query_data)\n+            query_data = parse_query_json(query)\n         except ValueError:\n             return None, \"Invalid query format. The query is not a valid JSON.\"\n", "issue": "\"'float' object is not iterable\" when using coordinates for MongoDB query\nI'm trying to run a query using **MongoDB** and the **[$geoNear](http://docs.mongodb.org/manual/reference/operator/aggregation/geoNear/)** function, but every time I type the origin coordinate using floats (to create a [GeoJSON Point](http://docs.mongodb.org/manual/reference/geojson/)), I get an error: [_from Python?_]\n\n `Error running query: 'float' object is not iterable`\n\nI'm trying to run the query below. The problem here is the `[ -22.910079, -43.205161 ]` part.\n\n``` json\n{\n  \"collection\": \"bus\",\n  \"aggregate\": [\n    { \n        \"$geoNear\": { \n            \"near\": { \"type\": \"Point\", \"coordinates\": [ -22.910079, -43.205161 ] },\n            \"maxDistance\": 100000000,\n            \"distanceField\": \"dist.calculated\",\n            \"includeLocs\": \"dist.location\",\n            \"spherical\": true\n        }\n    }    \n  ]\n}\n```\n\nHowever, if I use the coordinates with integers, such as `[ -22, -43 ]`, the query runs fine, but this coordinate is now meaningless, obviously. Here is an example that doesn't error:\n\n``` json\n{\n  \"collection\": \"bus\",\n  \"aggregate\": [\n    { \n        \"$geoNear\": { \n            \"near\": { \"type\": \"Point\", \"coordinates\": [ -22, -43 ] },\n            \"maxDistance\": 100000000,\n            \"distanceField\": \"dist.calculated\",\n            \"includeLocs\": \"dist.location\",\n            \"spherical\": true\n        }\n    }    \n  ]\n}\n```\n\n", "before_files": [{"content": "import json\nimport datetime\nimport logging\nimport re\nfrom dateutil.parser import parse\n\nfrom redash.utils import JSONEncoder\nfrom redash.query_runner import *\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    import pymongo\n    from bson.objectid import ObjectId\n    from bson.son import SON\n    enabled = True\n\nexcept ImportError:\n    enabled = False\n\n\nTYPES_MAP = {\n    str: TYPE_STRING,\n    unicode: TYPE_STRING,\n    int: TYPE_INTEGER,\n    long: TYPE_INTEGER,\n    float: TYPE_FLOAT,\n    bool: TYPE_BOOLEAN,\n    datetime.datetime: TYPE_DATETIME,\n}\n\ndate_regex = re.compile(\"ISODate\\(\\\"(.*)\\\"\\)\", re.IGNORECASE)\n\nclass MongoDBJSONEncoder(JSONEncoder):\n    def default(self, o):\n        if isinstance(o, ObjectId):\n            return str(o)\n\n        return super(MongoDBJSONEncoder, self).default(o)\n\n# Simple query example:\n#\n# {\n#     \"collection\" : \"my_collection\",\n#     \"query\" : {\n#         \"date\" : {\n#             \"$gt\" : \"ISODate(\\\"2015-01-15 11:41\\\")\",\n#         },\n#         \"type\" : 1\n#     },\n#     \"fields\" : {\n#         \"_id\" : 1,\n#         \"name\" : 2\n#     },\n#     \"sort\" : [\n#        {\n#             \"name\" : \"date\",\n#             \"direction\" : -1\n#        }\n#     ]\n#\n# }\n#\n#\n# Aggregation\n# ===========\n# Uses a syntax similar to the one used in PyMongo, however to support the\n# correct order of sorting, it uses a regular list for the \"$sort\" operation\n# that converts into a SON (sorted dictionary) object before execution.\n#\n# Aggregation query example:\n#\n# {\n#     \"collection\" : \"things\",\n#     \"aggregate\" : [\n#         {\n#             \"$unwind\" : \"$tags\"\n#         },\n#         {\n#             \"$group\" : {\n#                 \"_id\" : \"$tags\",\n#                 \"count\" : { \"$sum\" : 1 }\n#             }\n#         },\n#         {\n#             \"$sort\" : [\n#                 {\n#                     \"name\" : \"count\",\n#                     \"direction\" : -1\n#                 },\n#                 {\n#                     \"name\" : \"_id\",\n#                     \"direction\" : -1\n#                 }\n#             ]\n#         }\n#     ]\n# }\n#\n#\nclass MongoDB(BaseQueryRunner):\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            'type': 'object',\n            'properties': {\n                'connectionString': {\n                    'type': 'string',\n                    'title': 'Connection String'\n                },\n                'dbName': {\n                    'type': 'string',\n                    'title': \"Database Name\"\n                },\n                'replicaSetName': {\n                    'type': 'string',\n                    'title': 'Replica Set Name'\n                },\n            },\n            'required': ['connectionString']\n        }\n\n    @classmethod\n    def enabled(cls):\n        return enabled\n\n    @classmethod\n    def annotate_query(cls):\n        return False\n\n    def __init__(self, configuration_json):\n        super(MongoDB, self).__init__(configuration_json)\n\n        self.syntax = 'json'\n\n        self.db_name = self.configuration[\"dbName\"]\n\n        self.is_replica_set = True if \"replicaSetName\" in self.configuration and self.configuration[\"replicaSetName\"] else False\n\n    def _get_column_by_name(self, columns, column_name):\n        for c in columns:\n            if \"name\" in c and c[\"name\"] == column_name:\n                return c\n\n        return None\n\n    def _fix_dates(self, data):\n        for k in data:\n            if isinstance(data[k], list):\n                for i in range(0, len(data[k])):\n                    if isinstance(data[k][i], (str, unicode)):\n                        self._convert_date(data[k], i)\n                    elif not isinstance(data[k][i], (int)):\n                        self._fix_dates(data[k][i])\n\n            elif isinstance(data[k], dict):\n                self._fix_dates(data[k])\n            else:\n                if isinstance(data[k], (str, unicode)):\n                    self._convert_date(data, k)\n\n    def _convert_date(self, q, field_name):\n        m = date_regex.findall(q[field_name])\n        if len(m) > 0:\n            q[field_name] = parse(m[0], yearfirst=True)\n\n    def run_query(self, query):\n        if self.is_replica_set:\n            db_connection = pymongo.MongoReplicaSetClient(self.configuration[\"connectionString\"], replicaSet=self.configuration[\"replicaSetName\"])\n        else:\n            db_connection = pymongo.MongoClient(self.configuration[\"connectionString\"])\n\n        db = db_connection[self.db_name]\n\n        logger.debug(\"mongodb connection string: %s\", self.configuration['connectionString'])\n        logger.debug(\"mongodb got query: %s\", query)\n\n        try:\n            query_data = json.loads(query)\n            self._fix_dates(query_data)\n        except ValueError:\n            return None, \"Invalid query format. The query is not a valid JSON.\"\n\n        if \"collection\" not in query_data:\n            return None, \"'collection' must have a value to run a query\"\n        else:\n            collection = query_data[\"collection\"]\n\n        q = query_data.get(\"query\", None)\n        f = None\n\n        aggregate = query_data.get(\"aggregate\", None)\n        if aggregate:\n            for step in aggregate:\n                if \"$sort\" in step:\n                    sort_list = []\n                    for sort_item in step[\"$sort\"]:\n                        sort_list.append((sort_item[\"name\"], sort_item[\"direction\"]))\n\n                    step[\"$sort\"] = SON(sort_list)\n\n        if not aggregate:\n            s = None\n            if \"sort\" in query_data and query_data[\"sort\"]:\n                s = []\n                for field in query_data[\"sort\"]:\n                    s.append((field[\"name\"], field[\"direction\"]))\n\n        if \"fields\" in query_data:\n            f = query_data[\"fields\"]\n\n        s = None\n        if \"sort\" in query_data and query_data[\"sort\"]:\n            s = []\n            for field_data in query_data[\"sort\"]:\n                s.append((field_data[\"name\"], field_data[\"direction\"]))\n\n        columns = []\n        rows = []\n\n        cursor = None\n        if q or (not q and not aggregate):\n            if s:\n                cursor = db[collection].find(q, f).sort(s)\n            else:\n                cursor = db[collection].find(q, f)\n\n            if \"skip\" in query_data:\n                cursor = cursor.skip(query_data[\"skip\"])\n\n            if \"limit\" in query_data:\n                cursor = cursor.limit(query_data[\"limit\"])\n\n        elif aggregate:\n            r = db[collection].aggregate(aggregate)\n\n            # Backwards compatibility with older pymongo versions.\n            #\n            # Older pymongo version would return a dictionary from an aggregate command.\n            # The dict would contain a \"result\" key which would hold the cursor.\n            # Newer ones return pymongo.command_cursor.CommandCursor.\n            if isinstance(r, dict):\n                cursor = r[\"result\"]\n            else:\n                cursor = r\n\n        for r in cursor:\n            for k in r:\n                if self._get_column_by_name(columns, k) is None:\n                    columns.append({\n                        \"name\": k,\n                        \"friendly_name\": k,\n                        \"type\": TYPES_MAP.get(type(r[k]), TYPE_STRING)\n                    })\n\n            rows.append(r)\n\n        if f:\n            ordered_columns = []\n            for k in sorted(f, key=f.get):\n                ordered_columns.append(self._get_column_by_name(columns, k))\n\n            columns = ordered_columns\n\n        data = {\n            \"columns\": columns,\n            \"rows\": rows\n        }\n        error = None\n        json_data = json.dumps(data, cls=MongoDBJSONEncoder)\n\n        return json_data, error\n\nregister(MongoDB)\n", "path": "redash/query_runner/mongodb.py"}], "after_files": [{"content": "import json\nimport datetime\nimport logging\nimport re\nfrom dateutil.parser import parse\n\nfrom redash.utils import JSONEncoder\nfrom redash.query_runner import *\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    import pymongo\n    from bson.objectid import ObjectId\n    from bson.son import SON\n    enabled = True\n\nexcept ImportError:\n    enabled = False\n\n\nTYPES_MAP = {\n    str: TYPE_STRING,\n    unicode: TYPE_STRING,\n    int: TYPE_INTEGER,\n    long: TYPE_INTEGER,\n    float: TYPE_FLOAT,\n    bool: TYPE_BOOLEAN,\n    datetime.datetime: TYPE_DATETIME,\n}\n\n\nclass MongoDBJSONEncoder(JSONEncoder):\n    def default(self, o):\n        if isinstance(o, ObjectId):\n            return str(o)\n\n        return super(MongoDBJSONEncoder, self).default(o)\n\n\ndate_regex = re.compile(\"ISODate\\(\\\"(.*)\\\"\\)\", re.IGNORECASE)\n\n\ndef datetime_parser(dct):\n    for k, v in dct.iteritems():\n        if isinstance(v, basestring):\n            m = date_regex.findall(v)\n            if len(m) > 0:\n                dct[k] = parse(m[0], yearfirst=True)\n\n    return dct\n\n\ndef parse_query_json(query):\n    query_data = json.loads(query, object_hook=datetime_parser)\n    return query_data\n\n\nclass MongoDB(BaseQueryRunner):\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            'type': 'object',\n            'properties': {\n                'connectionString': {\n                    'type': 'string',\n                    'title': 'Connection String'\n                },\n                'dbName': {\n                    'type': 'string',\n                    'title': \"Database Name\"\n                },\n                'replicaSetName': {\n                    'type': 'string',\n                    'title': 'Replica Set Name'\n                },\n            },\n            'required': ['connectionString']\n        }\n\n    @classmethod\n    def enabled(cls):\n        return enabled\n\n    @classmethod\n    def annotate_query(cls):\n        return False\n\n    def __init__(self, configuration_json):\n        super(MongoDB, self).__init__(configuration_json)\n\n        self.syntax = 'json'\n\n        self.db_name = self.configuration[\"dbName\"]\n\n        self.is_replica_set = True if \"replicaSetName\" in self.configuration and self.configuration[\"replicaSetName\"] else False\n\n    def _get_column_by_name(self, columns, column_name):\n        for c in columns:\n            if \"name\" in c and c[\"name\"] == column_name:\n                return c\n\n        return None\n\n\n    def run_query(self, query):\n        if self.is_replica_set:\n            db_connection = pymongo.MongoReplicaSetClient(self.configuration[\"connectionString\"], replicaSet=self.configuration[\"replicaSetName\"])\n        else:\n            db_connection = pymongo.MongoClient(self.configuration[\"connectionString\"])\n\n        db = db_connection[self.db_name]\n\n        logger.debug(\"mongodb connection string: %s\", self.configuration['connectionString'])\n        logger.debug(\"mongodb got query: %s\", query)\n\n        try:\n            query_data = parse_query_json(query)\n        except ValueError:\n            return None, \"Invalid query format. The query is not a valid JSON.\"\n\n        if \"collection\" not in query_data:\n            return None, \"'collection' must have a value to run a query\"\n        else:\n            collection = query_data[\"collection\"]\n\n        q = query_data.get(\"query\", None)\n        f = None\n\n        aggregate = query_data.get(\"aggregate\", None)\n        if aggregate:\n            for step in aggregate:\n                if \"$sort\" in step:\n                    sort_list = []\n                    for sort_item in step[\"$sort\"]:\n                        sort_list.append((sort_item[\"name\"], sort_item[\"direction\"]))\n\n                    step[\"$sort\"] = SON(sort_list)\n\n        if not aggregate:\n            s = None\n            if \"sort\" in query_data and query_data[\"sort\"]:\n                s = []\n                for field in query_data[\"sort\"]:\n                    s.append((field[\"name\"], field[\"direction\"]))\n\n        if \"fields\" in query_data:\n            f = query_data[\"fields\"]\n\n        s = None\n        if \"sort\" in query_data and query_data[\"sort\"]:\n            s = []\n            for field_data in query_data[\"sort\"]:\n                s.append((field_data[\"name\"], field_data[\"direction\"]))\n\n        columns = []\n        rows = []\n\n        cursor = None\n        if q or (not q and not aggregate):\n            if s:\n                cursor = db[collection].find(q, f).sort(s)\n            else:\n                cursor = db[collection].find(q, f)\n\n            if \"skip\" in query_data:\n                cursor = cursor.skip(query_data[\"skip\"])\n\n            if \"limit\" in query_data:\n                cursor = cursor.limit(query_data[\"limit\"])\n\n        elif aggregate:\n            r = db[collection].aggregate(aggregate)\n\n            # Backwards compatibility with older pymongo versions.\n            #\n            # Older pymongo version would return a dictionary from an aggregate command.\n            # The dict would contain a \"result\" key which would hold the cursor.\n            # Newer ones return pymongo.command_cursor.CommandCursor.\n            if isinstance(r, dict):\n                cursor = r[\"result\"]\n            else:\n                cursor = r\n\n        for r in cursor:\n            for k in r:\n                if self._get_column_by_name(columns, k) is None:\n                    columns.append({\n                        \"name\": k,\n                        \"friendly_name\": k,\n                        \"type\": TYPES_MAP.get(type(r[k]), TYPE_STRING)\n                    })\n\n            rows.append(r)\n\n        if f:\n            ordered_columns = []\n            for k in sorted(f, key=f.get):\n                ordered_columns.append(self._get_column_by_name(columns, k))\n\n            columns = ordered_columns\n\n        data = {\n            \"columns\": columns,\n            \"rows\": rows\n        }\n        error = None\n        json_data = json.dumps(data, cls=MongoDBJSONEncoder)\n\n        return json_data, error\n\nregister(MongoDB)\n", "path": "redash/query_runner/mongodb.py"}]}