2013-12-15 13 views
6

Ho una semplice configurazione per client singolo per MongoDB e PyMongo 2.6.3. L'obiettivo è di scorrere su ciascun documento nella collezione collection e aggiornare (save) ogni documento nel processo. L'approccio che sto usando assomiglia grosso modo:Come iterare e aggiornare i documenti con PyMongo?

cursor = collection.find({}) 
index = 0 
count = cursor.count() 
while index != count: 
    doc = cursor[index] 
    print 'updating doc ' + doc['name'] 
    # modify doc .. 
    collection.save(doc) 
    index += 1 
cursor.close() 

Il problema è che save è apparentemente modificando l'ordine dei documenti nel cursore. Ad esempio, se la mia raccolta è composto da 3 documenti (id s omesso per chiarezza):

{ 
    "name": "one" 
} 
{ 
    "name": "two" 
} 
{ 
    "name": "three" 
} 

risultati del programma di cui sopra:

> updating doc one 
> updating doc two 
> updating doc two 

Se, tuttavia, la linea collection.save(doc) viene rimosso, l'uscita diventa:

> updating doc one 
> updating doc two 
> updating doc three 

Perché sta succedendo? Qual è il modo giusto per iterare in modo sicuro i documenti di aggiornamento e in una raccolta?

+0

Questa non è una risposta. Ma prova '1 + 999 è 1000' e' '1 + 999 == 1000'. – falsetru

+0

@falsetru thx stava semplicemente ricreando per semplicità, imparando ancora python :). ok ora? – paislee

+0

come stai modificando i documenti? è 'doc ['name'] = 'newValue'' abbastanza? –

risposta

10

trovato la risposta in MongoDB documentation:

Poiché il cursore non è isolato durante la sua vita, intervenendo operazioni di scrittura su un documento può genera un cursore che restituisce un documento più di una volta se quel documento è cambiato. Per gestire questa situazione, vedere le informazioni su snapshot mode.

modo foto è abilitato sul cursore, e fa una bella garanzia:

snapshot() attraversa l'indice sul campo _id e garantisce che la query restituirà ciascun documento (rispetto al valore di il campo _id) non più di una volta.

per abilitare la modalità istantanea con PyMongo:

cursor = collection.find(spec={},snapshot=True) 

secondo PyMongo find()documentation. Confermato che questo ha risolto il mio problema.

1

Non riesco a ricreare la tua situazione ma forse, in cima alla mia testa, perché recuperando i risultati come stai facendo, prendili uno a uno dal db, in realtà stai creando più mentre vai (salvando e poi recuperando il prossimo).

Si può provare a tenere il risultato in un elenco (in questo modo, il tuo recupero tutti i risultati in una sola volta - potrebbe essere pesante, a seconda della query):

cursor = collection.find({}) 
# index = 0 
results = [res for res in cursor] #count = cursor.count() 
cursor.close() 
for res in results: # while index != count //This will iterate the list without you needed to keep a counter: 
    # doc = cursor[index] // No need for this since 'res' holds the current record in the loop cycle 
    print 'updating doc ' + res['name'] # print 'updating doc ' + doc['name'] 
    # modify doc .. 
    collection.save(res) 
    # index += 1 // Again, no need for counter 

Speranza che aiuta

5

L'istantanea funziona.

Ma su pymongo 2.9 e versioni successive, la sintassi è leggermente diversa.

cursor = collection.find(modifiers={"$snapshot": True}) 

o per qualsiasi versione,

cursor = collection.find({"$snapshot": True}) 

come da PyMongo documentations

Problemi correlati