问题
I'm looking to create and handle a cursor in python the way cursors natively work in mongo. I know the intended way is to do 'result = collection.find()' and do a 'for record in result' but I'm looking to wrap iteration functionality in a class. I'd like to be able to create a new class object and call a function e.g. init_cursor() to make a db connection and do a find returning a cursor. I would then like the have a get_next() function that would move to the next result and set class data members based on the result. Here's the pesudo-code:
class dataIter():
def __init__(self):
self.collection = pymongo.Connection().db.collection
self.cursor = self.collection.find({}) #return all
self.age = None
self.gender = None
def get_next(self):
if self.cursor.hasNext():
data = self.cursor.next()
self.set_data(data)
def set_data(self, data):
self.age = data['age']
self.gender = data['gender']
This way I would be able to simply call:
obj.get_next()
age = obj.age
gender = obj.gender
or some other help functions to pull data out of each document
回答1:
I don't understand how what you are showing is any more convenient that just doing:
col = pymongo.Connection().db.collection
cur = col.find({})
obj = next(cur, None)
if obj:
age = obj['age']
gender = obj['gender']
Its not clear how this wrapper is helpful. Also, if what you are really after is an ORM, then don't reinvent the wheel when this exists: http://mongoengine.org/
回答2:
You should use the python iterator protocol, you class can look like this
class DataIter:
def __init__(self):
self.collection = pymongo.Connection().db.collection
self.cursor = self.collection.find({}) #return all
self.age = None
self.gender = None
def __iter__(self):
return self
def next(self):
if self.cursor.hasNext():
data = self.cursor.next()
self.set_data(data)
return self
else:
raise StopIteration
Then you can iterate like this
for c in DataIter():
age = c.age
gender = c.gender
回答3:
You can use something like what you have posted already to accomplish this. PyMongo cursors don't have a haveNext
method, but they have a next
method which will either return the next document, or raise StopIteration
(this is specified by the Python iterator protocol).
You can also take this a step further: rather than assigning the values from the document to attributes on the class, you can use __getattr__
which implements attribute lookup for Python classes.
Putting it all together, you might end up with something like:
class DataIter(object):
def __init__(self, cursor):
self._cursor = cursor
self._doc = None
def next(self):
try:
self._doc = self._cursor.next()
except StopIteration:
self._doc = None
return self
def __getattr__(self, key):
try:
return self._doc[key]
except KeyError:
raise AttributeError('document has no attribute %r' % name)
回答4:
Here's what I ended up going with:
class Cursor(object):
def __init__(self):
# mongo connection
self.collection = pymongo.Connection().cursorcollection
self.loaded = False
self.cursor = None
# Cursor calls (for iterating through results)
def init_cursor(self):
""" Opens a new cursor """
if not self.cursor:
self.cursor = self.collection.find({})
def get_next(self):
""" load next object """
if self.cursor and self.cursor.alive:
self.set_data(next(self.cursor))
return True
else:
self.cursor = None
return False
def has_next(self):
""" cursor alive? """
if self.cursor and self.cursor.alive:
return True
else:
return False
来源:https://stackoverflow.com/questions/10424078/pymongo-cursor-iteration