我需要在Python代码中读取MongoDB的整个集合(集合名称为“test”)。我试过像
self.__connection__ = Connection('localhost',27017)
dbh = self.__connection__['test_db']
collection = dbh['test']
如何通过1000读取块中的集合(以避免内存溢出,因为集合可能非常大)?
答案 0 :(得分:6)
我同意雷蒙的意见,但是你提到了1000批,他的回答并没有真正涵盖。您可以在光标上设置批量大小:
cursor.batch_size(1000);
您也可以跳过记录,例如:
cursor.skip(4000);
这是你要找的吗?这实际上是一种分页模式。但是,如果您只是想避免内存耗尽,那么您实际上并不需要设置批量大小或跳过。
答案 1 :(得分:5)
使用游标。游标有一个" batchSize"变量,用于控制在执行查询后每批实际发送到客户端的文档数。你不必触摸这个设置,因为默认是好的,如果调用" getmore"大多数驱动程序都隐藏了命令。我不熟悉pymongo,但它的工作原理如下:
cursor = db.col.find() // Get everything!
while(cursor.hasNext()) {
/* This will use the documents already fetched and if it runs out of documents in it's local batch it will fetch another X of them from the server (where X is batchSize). */
document = cursor.next();
// Do your magic here
}
答案 2 :(得分:2)
在@Rafael Valero的启发下+修复了他代码中的最后一个小块错误,并使其更加通用,我创建了生成器函数来遍历带有查询和投影的mongo集合:
def iterate_by_chunks(collection, chunksize=1, start_from=0, query={}, projection={}):
chunks = range(start_from, collection.find(query).count(), int(chunksize))
num_chunks = len(chunks)
for i in range(1,num_chunks+1):
if i < num_chunks:
yield collection.find(query, projection=projection)[chunks[i-1]:chunks[i]]
else:
yield collection.find(query, projection=projection)[chunks[i-1]:chunks.stop]
例如,您首先创建一个这样的迭代器:
mess_chunk_iter = iterate_by_chunks(db_local.conversation_messages, 200, 0, query={}, projection=projection)
然后按块进行迭代:
chunk_n=0
total_docs=0
for docs in mess_chunk_iter:
chunk_n=chunk_n+1
chunk_len = 0
for d in docs:
chunk_len=chunk_len+1
total_docs=total_docs+1
print(f'chunk #: {chunk_n}, chunk_len: {chunk_len}')
print("total docs iterated: ", total_docs)
chunk #: 1, chunk_len: 400
chunk #: 2, chunk_len: 400
chunk #: 3, chunk_len: 400
chunk #: 4, chunk_len: 400
chunk #: 5, chunk_len: 400
chunk #: 6, chunk_len: 400
chunk #: 7, chunk_len: 281
total docs iterated: 2681
答案 3 :(得分:1)
这是一种通用解决方案,可以批量迭代任何迭代器或生成器:
def _as_batch(cursor, batch_size=50):
# iterate over something (pymongo cursor, generator, ...) by batch.
# Note: the last batch may contain less than batch_size elements.
batch = []
try:
while True:
for _ in range(batch_size):
batch.append(next(cursor))
yield batch
batch = []
except StopIteration as e:
if len(batch):
yield batch
只要cursor
定义了方法__next__
(即我们可以使用next(cursor)
),此方法就起作用。因此,我们可以在原始光标或转换后的记录上使用它。
示例
简单用法:
for batch in db['coll_name'].find():
# do stuff
更复杂的用法(例如,用于批量更新):
def update_func(doc):
# dummy transform function
doc['y'] = doc['x'] + 1
return doc
query = (update_func(doc) for doc in db['coll_name'].find())
for batch in _as_batch(query):
# do stuff
重新实现count()
函数:
sum(map(len, _as_batch( db['coll_name'].find() )))
答案 4 :(得分:0)
使用Pymongo创建当前在Python 2中的初始连接:
host = 'localhost'
port = 27017
db_name = 'test_db'
collection_name = 'test'
使用MongoClient进行连接
# Connect to MongoDB
client = MongoClient(host=host, port=port)
# Make a query to the specific DB and Collection
dbh = client[dbname]
collection = dbh[collection_name]
所以从这里得到正确答案。 我想通过使用块来读取(在这种情况下,大小为1000)。
chunksize = 1000
例如,我们可以决定我们想要多少块大小(chunksize)。
# Some variables to create the chunks
skips_variable = range(0, db_aux[collection].find(query).count(), int(chunksize))
if len(skips_variable)<=1:
skips_variable = [0,len(skips_variable)]
然后我们可以检索每个块。
for i in range(1,len(skips_variable)):
# Expand the cursor and retrieve data
data_from_chunk = dbh[collection_name].find(query)[skips_variable[i-1]:skips_variable[i]]))
本案例中的查询为query = {}
。
Here我使用类似的想法从MongoDB创建数据帧。 Here我使用类似的东西以块的形式写入MongoDB。
我希望它有所帮助。