Skip to content

Commit

Permalink
Added support for running MongoDB queries on secondary in replicaset …
Browse files Browse the repository at this point in the history
…mode (#1424)

* - Added support to specify read preference when query a replicaset database (for example, secondaryPreferred - to try and read data from secondary before primary).
- Removed old code that used MongoClientReplicaSet as it is now just a reference to MongoClient
- Fixed a documentation type :-)

* Moving to PyMongo 3.3.1 which also supports MongoDB 3.2

* Changed the readPreference config to use an enum

* Pass readPreference to MongoClient

* primaryPreferred is now the default
  • Loading branch information
erans authored and arikfr committed Jan 23, 2020
1 parent 35e4138 commit 7d11fae
Showing 1 changed file with 31 additions and 6 deletions.
37 changes: 31 additions & 6 deletions redash/query_runner/mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,31 @@ class MongoDB(BaseQueryRunner):
@classmethod
def configuration_schema(cls):
return {
"type": "object",
"properties": {
"connectionString": {"type": "string", "title": "Connection String"},
"dbName": {"type": "string", "title": "Database Name"},
"replicaSetName": {"type": "string", "title": "Replica Set Name"},
'type': 'object',
'properties': {
'connectionString': {
'type': 'string',
'title': 'Connection String'
},
'dbName': {
'type': 'string',
'title': "Database Name"
},
'replicaSetName': {
'type': 'string',
'title': 'Replica Set Name'
},
"readPreference": {
"type": "string",
"extendedEnum": [
{"value": "primaryPreferred", "name": "Primary Preferred"},
{"value": "primary", "name": "Primary"},
{"value": "secondary", "name": "Secondary"},
{"value": "secondaryPreferred", "name": "Secondary Preferred"},
{"value": "nearest", "name": "Nearest"},
],
"title": "Replica Set Read Preference",
}
},
"required": ["connectionString", "dbName"],
}
Expand All @@ -158,10 +178,12 @@ def __init__(self, configuration):
)

def _get_db(self):
kwargs = {}
if self.is_replica_set:
db_connection = pymongo.MongoClient(
self.configuration["connectionString"],
replicaSet=self.configuration["replicaSetName"],
readPreference=self.configuration["readPreference"]
)
else:
db_connection = pymongo.MongoClient(self.configuration["connectionString"])
Expand All @@ -173,6 +195,9 @@ def test_connection(self):
if not db.command("connectionStatus")["ok"]:
raise Exception("MongoDB connection error")

return db_connection[self.db_name]


def _merge_property_names(self, columns, document):
for property in document:
if property not in columns:
Expand All @@ -192,7 +217,7 @@ def _get_collection_fields(self, db, collection_name):
# For now, the logic is to take the first and last documents (last is determined
# by the Natural Order (http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order)
# as we don't know the correct order. In most single server installations it would be
# find. In replicaset when reading from non master it might not return the really last
# fine. In replicaset when reading from non master it might not return the really last
# document written.
collection_is_a_view = self._is_collection_a_view(db, collection_name)
documents_sample = []
Expand Down

0 comments on commit 7d11fae

Please sign in to comment.