2016-09-21 60 views
3

我有一個包含500K +文檔的集合,存儲在單個節點mongo上。每隔一段時間我的pymongo cursor.find()都會失敗,因爲它會超時。使用生成器遍歷Mongo中的大集合

雖然我可以設置find忽略超時,但我不喜歡這種方法。相反,我嘗試了發電機(改編自this答案,this鏈接):

def mongo_iterator(self, cursor, limit=1000): 
     skip = 0 
     while True: 
      results = cursor.find({}).sort("signature", 1).skip(skip).limit(limit) 

      try: 
       results.next() 

      except StopIteration: 
       break 

      for result in results: 
       yield result 

      skip += limit 

然後我用調用這個方法:

ref_results_iter = self.mongo_iterator(cursor=latest_rents_refs, limit=50000) 
for ref in ref_results_iter: 
    results_latest1.append(ref) 

問題: 我的迭代器不返回相同數量的結果。問題是next()會提前移動光標。因此,對於每一個電話,我失去了一個元素...

問題: 有沒有一種方法來適應此代碼,以便我可以檢查下一個存在? Pymongo 3x不提供hasNext()和'alive'檢查is not guaranteed以返回false。

+0

'0到1000'等於'[0,1,2,3 ......,999]',下一個開始是'1000',但你會失去一個(可能是last_one)。所以'索引號不等於length_number'。 – dsgdfg

+0

它會說'first_result_in_batch = results.next()',從而捕獲你目前丟棄的元素(如果有的話)?然後你可以在for循環中放置'yield first_result_in_batch',從而以正確的順序將該元素賦給調用者。 (我不知道MongoDB,所以也許我錯過了一些東西。) –

回答

1

爲什麼不使用

for result in results: 
    yield result 

for循環應處理StopIteration你。

+0

它確實停止了,但我需要知道並處理外部迭代和跳過(例如,獲取第一個10,000,進程,獲取下一個10,000進程等)。正如我所說的,問題在於「停止」不會丟失數據。 – goggelj

+0

這不是答案!已經'結果'有1000個元素。 – dsgdfg

+0

@dsgdfg你錯過了整個觀點。我同意你已經有1000個,但是由於next()你只丟了一個。我想唯一的方法是執行「計數」並從迭代器中取出跳過/限制邏輯。 – goggelj

1

.find()方法需要額外的關鍵字參數。其中之一是no_cursor_timeout,你需要設置True

cursor = collection.find({}, no_cursor_timeout=True) 

你不需要寫自己的發電機的功能。 find()方法返回一個像對象一樣的生成器。

+0

將超時設置爲False會導致我不得不彈回虛擬機......它只是掛起。 – goggelj