PyMongo не перебирает сбор

У меня странное поведение в Python/PyMongo.

dbh = self.__connection__['test']
first = dbh['test_1']
second = dbh['test_2']
first_collection_records=first.find() 
second_collection_records=second.find()
index_f=first_collection_records.count() //20 
index_s=second_collection_records.count() //120
i=0
for f in first_collection_records:
 for s in second_collection_records:
 i=i+1
 print i

и он печатает только 120 раз (1..120), а не 20x120 раз. Может ли кто-нибудь сказать мне, почему он не перебирает внешнюю коллекцию? Я печатал результаты, он всегда занимает только первый из внешних и итераций над внутренней коллекцией. (Я отправил подсчеты, которые я получаю в коде 20 и 120, я попробовал с xrange и fetch по индексу, но ничего)

1 ответ

Если вы хотите итерации second_collection_records для каждого first_collection_records, вы можете использовать:

i=0
for f in first_collection_records:
 second_collection_records.rewind() #Reset second_collection_records iterator
 for s in second_collection_records:
 i=i+1
 print i

. return() сбрасывает курсор в новое состояние, позволяя вам снова извлекать данные в second_collection_records.

Объяснение:

second.find()

возвращает объект Cursor, содержащий итератор.

Когда итератор курсора достигнет своего конца, он больше ничего не возвращает.

следующим образом:

for f in first_collection_records: #20

на самом деле выполняет итерацию 20 раз, но поскольку внутренний:

for s in second_collection_records:

уже повторил все возвращенные объекты, второй раз, когда он вызывается, second_collection_records больше ничего не возвращает, поэтому код внутри (i = я + 1, print...) не выполняется.

Вы можете попробовать это следующим образом:

i = 0
for f in first_collection_records:
 print "in f"
 for s in second_collection_records: 
 print "inside s"

Вы получите результат:

inside f
inside s
inside s
...
inside s
inside f <- since s has nothing left to be iterated, 
 (second_collection_records actually raised StopIteration such in generator),
 code inside for s in second_collection_records: is no longer executed
inside f
inside f

Подробное объяснение:

Эта строка:

for s in second_collection_records:

цикл здесь фактически работает методом next() объекта Cursor, как в: вызове second_collection_records.next(), пока second_collection_records не вызвал исключение StopIteration (в генераторе Python и для цикла StopIteration пойман, а код внутри цикла не будет выполняется). Таким образом, во втором последнем цикле first_collection_records, second_collection_records.next() фактически поднял StopIteration для внутреннего цикла, не выполняя код.

Мы можем легко наблюдать это поведение, делая следующее:

for f in first_collection_records:
 print "inside f"
 second_collection_records.next()
 for s in second_collection_records:
 print "inside s"

И результат:

inside f
inside s
...
inside s
inside f
Traceback (most recent call last):
 ... , in next
 raise StopIteration
StopIteration

licensed under cc by-sa 3.0 with attribution.