2013-11-28 3 views
0

내가 노드/익스프레스/MongoDB를/Mongoskin와 응용 프로그램을 짓고 있어요

나는 문서의 모음 갱신이 코드가 있습니다

db.collection('invoices').find().toArray(function(err, dbDocs) { 
    if (err) throw err; 

    // Change one, none or several fields named 'paid' in the fetched invoices array 
    ... 

    // Loop trough the changed dbDocs and use it to update the database. 
    for (var i = 0, j = dbDocs.length; i < j; i += 1) { 
    db.collection('invoices').update({_id:dbDocs[i]._id}, {$set:{ paid: dbDocs[i].paid }}, function(err, result) { 
     if (err) throw err; 

     // Trigger a redirect after the last iteration. 
     if (!err && (i === dbDocs.length - 1)) { 
     console.log('"i" is right now: ', i); 
     res.redirect('/superadmin/fakturor'); 
     } 
    }); 
    } 
}); 

을 update() 함수가 콜백을 가지고 있고 콜백이 마침내 발생하면 for-loop가 이미 끝났기 때문에 리디렉션이 네 번 호출됩니다. 리디렉션이 한 번 호출되도록 지정합니다. 즉, 마지막 반복 이후이며 오류가 없습니다.

어떻게 작동하도록이 코드를 다시 작성합니까?

답변

1

먼저 마음 i = dbDocs.length 그것을해야한다 : 이제 i == dbDocs.length-1

,이 시도 :

for (var i = 0; i < dbDocs.length; i += 1) { 
    (function (i) { 
     db.collection('invoices').update({ _id: dbDocs[i]._id }, { $set: { paid: dbDocs[i].paid } }, function (err, result) { 
      if (err) throw err; 

      // Trigger a redirect after the last iteration. 
      if (!err && (i == dbDocs.length-1)) { 
       console.log('i: ', i); 
       res.redirect('/superadmin/fakturor'); 
      } 
     }); 
    })(i) 
} 
} 
+0

이 코드는 작동합니다! 이 기능을 사용하는 이러한 패턴을 인식하지만 어떻게 작동하는지 잘 모르겠습니다. 말로 설명해 주시겠습니까?이 패턴에 "이름"이 있는지 아십니까? –

+1

기본적으로 문제는 콜백 함수가 호출 될 때 for 루프가 이미 끝났기 때문에'i' 변수가'dbDocs.length'와 동일하다는 것입니다. 이 트릭은 익명의 함수를 생성하고'i' 변수가 적절한 값을 가질 때 그것을 호출합니다. 함수를 호출하면 'i'의 값이 복사되므로 'i'의 스냅 샷을 찍는 것과 같습니다. 이제 JS에서 매우 자주 발생하는 문제입니다. 자세한 내용은 JS에 자세히 나와 있습니다. 나는 이름을 모르지만 루프 변수 *를 가진 콜백과 같은 것을 호출 할 것이다. –

1

를 이것은 당신이 다루는 일부 도우미 기능을 사용할 수있는에서 async library의 일반적인 사용 사례 귀하 동시성 문제.

async.each(arr, iterator, callback)을 사용할 수 있으며 배열의 각 구성원에 iterator()이 호출됩니다. 모든 반복기가 완료되면 callback 함수가 호출됩니다.

var async = require('async'); 

var updateDoc = function (elem, cb) { 
    db.collection('invoices').update({_id:elem._id}, {$set:{ paid: elem.paid }}, cb); 
} 

var done = function (err) { 
    if (err) 
    return console.error(err.message); 
    res.redirect('/superadmin/fakturor'); 
} 

async.each(dbDocs, updateDoc, done);