2014-05-19 3 views
0
Scenario: There are users and users has many posts. For a particular group of users, I need to fetch 10 recent posts per user and send them in response. 
Here is what I have come up with: 

사용자는 사용자 정보가있는 배열입니다. 이제 NodeJS MongoDB의 중첩 for 루프 및 콜백에서 실행 순서 유지

var allPosts = []; 

for(var i=0; i<users.length; i++){ 
    (function(i){            //Level-1 
     db.collection('posts', function(err, postCollection){ 
      (function(i){          //Level-2 
       postCollection.find({"user_id": users[i]['user_id']}).sort({"created": -1}).limit(10).toArray(function(err, post) { 
        (function(i){        //Level-3 
         for(var j =0; j< post.length; j++){ 
          (function(j){ 
           post[j]['created'] = ObjectId(post[j]['_id'].toString()).getTimestamp(); 
           allPosts.push(post[j]); 
           if(j === post.length-1){ 
            res.send(allPosts); 
           } 
          })(j); 
         }  
        })(i); 
       }); 
      })(i); 
     });  
    })(i);       
} 

은, 실행 순서는 레벨 2까지 보존되어 있지만 레벨 3에 진입 할 때, 모든 것이 단지 잘못 : 나는 배열에 두 명의 사용자가 하나의 사용자가 3 개 게시물을 가지고 있으며, 또 다른 10있다 게시물, 때로는 응답은 3 개의 게시물과 때로는 모든 13 개의 게시물입니다. MongoDB 덕분이라고 생각합니다. 즉시 호출 된 함수 식 (IIFE)을 사용하여 실행 순서를 처리하기도하지만 여기서는 작동하지 않는 것 같습니다. 도움을 주시면 감사하겠습니다. 감사합니다.

답변

1

먼저 코드를 아름답게 꾸며야합니다. 다른 루프의 콜백 내부에서 익명 함수를 루프 내부에서 사용하는 것은 유지 보수 나 읽기가 쉽지 않습니다.

마지막 루프 (j 루프)에서 다른 사용자에 대한 쿼리가 완료되기 전에 j == users.length - 1에 도달하기 때문에 응답이 완료된 게시물 쿼리 수와 함께 전송됩니다. 그 순간까지.

또 다른 큰 실수는 게시물 컬렉션을 루프 안에 요청했다는 것입니다. 그건 틀렸어! 데이터베이스와 컬렉션을 캐시해야합니다.

var allPosts = []; 
var post_collection = null; 

var get_user = function(i, callback) { 
    post_collection 
     .find({"user_id": users[i]['user_id']}) 
     .sort({"created": -1}) 
     .limit(10) 
     .toArray(function(err, post) { 

      // Do something when you get error 
      // Always call the callback function if there is one 
      if(err) { 
       callback(); 
       return; 
      } 

      for(var j=0; j<post.length; ++j) { 
       post[j]['created'] = ObjectId(post[j]['_id'].toString()).getTimestamp(); 
       allPosts.push(post[j]); 
      } 

      callback(); 
     }); 
}; 

var fetch_users = function() { 
    var count = users.length; 

    for(var i=0; i<users.length; ++i) { 
     get_user(i, function() { 
      // Each time a query for one user is done we decrement the counter 
      count--; 

      // When the counter is 0 we know that all queries have been done 
      if(count === 0) { 
       res.send(allPosts); 
      } 
     }); 
    };  
}; 

// Get the collection, check for errors and then cache it! 
db.collection('posts', function(err, postCollection) { 

    // Always check for database errors 
    if(err) { 
     console.log(err); 
     return; 
    } 

    post_collection = postCollection; 
    fetch_users(); 
}); 

당신은이 코드는 테스트되지 않는다는 것을 알아야한다 :

이 코드를 사용해보십시오. 세미콜론이나 중괄호를 놓친 것일 수도 있지만 쉽게 알아낼 수 있습니다.

+0

감사합니다. @ 카탈로니아 어, 완벽하게 작동합니다. 조금 수정 : get_user if (j === post.length-1) {callback();}에서 콜백을 호출하기 전에 확인해야합니다. 또한 귀하의 조언과 짧은 시간에 나를 도와 주셔서 감사합니다. –

+0

네 말이 맞지만 if 문은 필요 없습니다. 사실 그 콜백은 루프 다음에 있어야합니다. 나는 대답을 편집했다. 또한 코드에서 변경해야합니다. –

+0

예, 루프 외부에서도 작동합니다. 다시 한 번 감사드립니다. :) –