2014-05-19 40 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: 

用戶是具有用戶信息的數組。保留嵌套for循環中的執行順序和NodeJS中的回調MongoDB

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);       
} 

現在,執行順序最多保留到Level-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

謝謝@Catalin,它工作得很好。稍作修改:需要在調用get_user中的回調之前檢查if(j === post.length-1){callback();}。此外,感謝您的建議,並幫助我在如此短的時間內 –

+0

是的你是對的,但你不需要if語句。實際上,回調應該在循環之後。我編輯了答案。您還應該在代碼中更改它。 –

+0

是的,它也可以在循環外工作,再次感謝:) –