Package json_to_relation :: Module mongodb
[hide private]
[frames] | no frames]

Source Code for Module json_to_relation.mongodb

  1   
  2   
  3  from pymongo import MongoClient 
  4   
  5   
6 -class MongoDB(object):
7 ''' 8 Very simple Python interface to MongoDB. Based on pymongo, 9 this class provides methods to get and set default databases 10 and collections, to insert documents, query collections, and 11 clear all documents in a collection. 12 13 The query() method encapsulates MangoDB native methods find() 14 and find_one(). The query() method makes it very convenient to 15 to request only particular sets of fields (columns in relational 16 terms). Example:: 17 myMongoDb.query({'lname' : 'Doe'}, ('fname', 'lname', 'age')) 18 ''' 19 20 # Map of query strings to MongoDB cursors. Administered 21 # by query() method. Used in resultCount(): 22 queryCursors = {} 23 24 # ---------------------------- Public Methods ------------------- 25
26 - def __init__(self, host="localhost", ssl_keyfile=None, dbName="test", collection="test_collection", port=27017, user=None, pwd=""):
27 ''' 28 Create a connection to the MongoDB demon on the given host/port. 29 @param host: host name where MongoDB demon is running. Can be IP address as string. 30 @type host: String 31 @param port: MongoDB demon's port 32 @type port: int 33 ''' 34 self.host = host 35 self.port = port 36 self.dbName = dbName 37 self.collection = collection 38 if user is not None: 39 # Use Mongodb URI, mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] 40 # e.g.: mongodb://readonly:xxxxx@stanford-edx-prod.m0.mongolayer.com/stanford-edx-prod) 41 if ssl_keyfile is None: 42 self.client=MongoClient("mongodb://%s:%s@%s/%s" % (user,pwd,host,dbName), port) 43 else: 44 self.client=MongoClient("mongodb://%s:%s@%s/%s" % (user,pwd,host,dbName), port, ssl_keyfile=ssl_keyfile) 45 else: 46 if ssl_keyfile is None: 47 self.client=MongoClient("mongodb://%s/%s" % (host,dbName), port) 48 else: 49 self.client=MongoClient("mongodb://%s/%s" % (host,dbName), port, ssl_keyfile=ssl_keyfile) 50 self.setDB(dbName) 51 self.setCollection(collection)
52
53 - def setDB(self, dbName):
54 ''' 55 Establish a default database within MongoDB for subsequent calls 56 to other methods of this class. 57 @param dbName: MongoDB database name 58 @type dbName: String 59 ''' 60 self.dbName = dbName 61 self.db = self.client[dbName]
62
63 - def getDBName(self):
64 ''' 65 Obtain the name of the MongoDB database that is 66 currently the default for calls to methods of this class. 67 @rtype: String 68 ''' 69 return self.dbName
70
71 - def setCollection(self, collName):
72 ''' 73 Establish a default MongoDB collection for subsequent calls to 74 other methods of this class. 75 @param collName: MongoDB collection name 76 @type collName: String 77 ''' 78 self.coll = self.db[collName]
79
80 - def getCollectionName(self):
81 ''' 82 Obtain the name of the MongoDB collection that is 83 currently the default for calls to methods of this class. 84 @rtype: String 85 ''' 86 return self.coll.name
87
88 - def query(self, mongoQuery, colNameTuple=(), limit=0, db=None, collection=None):
89 ''' 90 Method for querying the database. The mongoQuery parameter is a 91 dictionary conforming to the MongoDB query conventions. This query 92 is passed through to the underlying MongoDB. 93 94 The colNameTuple contains a list of field (a.k.a. relational column) names. 95 Result documents will contain only those fields. In contrast to MangoDB 96 convention, the _id field is not automatically returned in the result dictionaries. 97 This field is only included if the caller lists it in colNameTuple. If colNameTuple 98 is an empty tuple, the entirety of each document is returned for each query result. 99 100 The limit parameter determines how many documents will be returned. A value of zero 101 returns the entire result set. A value of 1 makes the method's behavior analogous to 102 MangoDB's native find_one() method. 103 104 The db and collection keyword arguments allow callers to address a MongoDB database 105 and/or collection that are not the default. After the method returns, the default 106 database and collection values will still be untouched. 107 108 @param mongoQuery: MangoDB query 109 @type mongoQuery: Dict<String,<any>> 110 @param colNameTuple: a possibly empty tuple of field/column names to retrieve for each result document 111 @type colNameTuple: (String) 112 @param limit: maximum number of documents to return 113 @type limit: int 114 @param db: name of MongoDB database other than the current default 115 @type db: String 116 @param collection: name of MongoDB collection other than the current default 117 @type collection: String 118 @rtype: {generator<ResultDict>} 119 ''' 120 with newMongoDB(self, db) as db, newMongoColl(self, collection) as coll: 121 # Turn the list of column names to return into 122 # Mongo-speak. First, take care of the Python weirdness 123 # that turn single-element tuples into the element 124 # themselve: ("foo", "bar") ---> ("foo", "bar"). BUT 125 # ("foo") ---> "foo". Whereas 126 # ("foo,") ---> ("foo",). Whereas 127 if not isinstance(colNameTuple, tuple): 128 colNameTuple = (str(colNameTuple),) 129 130 # Create dict {"colName1" : 1, "colName2" : 1,...} 131 colsToReturn = {} 132 for colName in colNameTuple: 133 colsToReturn[colName] = 1 134 # MongoDB insists on returning the '_id' field, even 135 # if you don't ask for it. Suppress that behavior 136 # iff (i) caller did specify at least one col name (i.e. 137 # didn't just pass in an empty tuple to get all 138 # columns, but also (ii) did *not* ask for '_id' 139 try: 140 if len(colsToReturn) > 0 and colsToReturn['_id']: 141 pass 142 except KeyError: 143 # Caller did not explicitly ask for the _id field, 144 # yet did ask for at least *one* col name. So 145 # suppress _id: 146 colsToReturn['_id'] = 0 147 148 if len(colsToReturn) > 0: 149 cursor = coll.find(mongoQuery, colsToReturn, limit=limit) 150 else: 151 cursor = coll.find(mongoQuery, limit=limit) 152 # Make the cursor findable, so that callers can ask for number of results 153 MongoDB.queryCursors[str(mongoQuery)] = cursor 154 while True: 155 # Termination happens when cursor is exhausted: 156 try: 157 yield cursor.next() 158 except: 159 # Cursor is exhausted, remove it from our 160 # records: 161 del(MongoDB.queryCursors[str(mongoQuery)]) 162 return
163
164 - def resultCount(self, queryDict):
165 ''' 166 Return number of results in the given query. Only works 167 when query has previously been issued via the query() 168 method AND at least one result has been extracted. That's 169 because the first call to query() only returns a generator. 170 This isn't good. 171 @param queryDict: Same query that was provided to the query() method 172 @type queryDict: Dict<String,<any>> 173 @return: number of results, taking into account limit provided to query(). None if no result has been pulled from query() 174 @rtype: {int | None} 175 ''' 176 try: 177 cursor = MongoDB.queryCursors[str(queryDict)] 178 return cursor.count(with_limit_and_skip=True) 179 except KeyError: 180 #raise ValueError("Called resultCount() with a query string that was not used in a prior call to query(), or the query results have all been retrieved.") 181 return None
182
183 - def clearCollection(self, db=None, collection=None):
184 ''' 185 Remove all documents from a collection. The affected database/collection 186 are the current defaults, if database/collection are None, else the specified 187 database/collection is affected. 188 @param db: Name of MongoDB database, or None 189 @type db: String 190 @param collection: Name of MongoDB collection, or None 191 @type collection: String 192 ''' 193 with newMongoDB(self, db) as db, newMongoColl(self, collection) as coll: 194 coll.remove()
195
196 - def dropCollection(self, db=None, collection=None):
197 ''' 198 Remove a collection from the database. The affected database/collection 199 are the current defaults, if database/collection are None, else the specified 200 database/collection is affected. 201 @param db: Name of MongoDB database, or None 202 @type db: String 203 @param collection: Name of MongoDB collection, or None 204 @type collection: String 205 ''' 206 with newMongoDB(self, db) as db, newMongoColl(self, collection) as coll: 207 coll.drop()
208 209
210 - def insert(self, doc_or_docs, db=None, collection=None):
211 ''' 212 Insert the given dictionary into a MongoDB collection. 213 @param doc_or_docs: Dictionary whose entries are the documents 214 @type doc_or_docs: Dict<String,<any>> 215 @param db: Name of MongoDB database, or None 216 @type db: String 217 @param collection: Name of MongoDB collection, or None 218 @type collection: String 219 ''' 220 with newMongoDB(self, db) as db, newMongoColl(self, collection) as coll: 221 coll.insert(doc_or_docs)
222 223
224 - def close(self):
225 ''' 226 Release all resources. 227 ''' 228 for cursor in MongoDB.queryCursors.values(): 229 try: 230 cursor.close() 231 except: 232 pass 233 self.client.close()
234 235 # ---------------------------- Private Methods ------------------- 236
237 - def get_db(self):
238 ''' 239 Obtain current default MongoDB database object 240 ''' 241 return self.db
242
243 - def get_collection(self):
244 ''' 245 Obtain current default MongoDB database object 246 ''' 247 return self.coll
248 249 # ---------------------------- Private Classes ------------------- 250
251 -class newMongoDB:
252 ''' 253 Class that enables the construct "with newMongoDB('myDB') as db:" 254 See http://effbot.org/zone/python-with-statement.htm for explanation 255 ''' 256
257 - def __init__(self, mongoObj, newDbName):
258 self.mongoObj = mongoObj 259 self.newDbName = newDbName
260
261 - def __enter__(self):
262 self.savedDBName = self.mongoObj.getDBName() 263 if self.newDbName is not None: 264 self.mongoObj.setDB(self.newDbName) 265 return self.mongoObj.get_db()
266
267 - def __exit__(self, errType, errValue, errTraceback):
268 self.mongoObj.setDB(self.savedDBName) 269 # Have any exception re-raised: 270 return False
271 272
273 -class newMongoColl:
274 ''' 275 Class that enables the construct "with newMongoColl('myColl') as coll:" 276 See http://effbot.org/zone/python-with-statement.htm for explanation 277 ''' 278
279 - def __init__(self, mongoObj, newCollName):
280 self.mongoObj = mongoObj 281 self.newCollName = newCollName
282
283 - def __enter__(self):
284 self.savedCollName = self.mongoObj.getCollectionName() 285 if self.newCollName is not None: 286 self.mongoObj.setCollection(self.newCollName) 287 return self.mongoObj.get_collection()
288
289 - def __exit__(self, errType, errValue, errTraceback):
290 self.mongoObj.setCollection(self.savedCollName) 291 # Have any exception re-raised: 292 return False
293