2015-10-05 27 views
0

我有以下一段代碼,我遍歷一個集合並執行另一個db查詢並在其回調中構造一個對象。最後,我將該對象保存到另一個集合中。nodejs和mongoskin,在保存所有項目後回調

我希望在保存所有項目後調用另一個函數,但不知道如何。我嘗試使用異步庫,特別是異步,而當項不是null,但只是引發我在一個無限循環。

有沒有一種方法來識別所有物品何時被保存?

謝謝!

var cursor = db.collection('user_apps').find({}, {timeout:false}); 
cursor.each(function (err, item) { 
    if (err) { 
     throw err; 
    } 
    if (item) { 
     var appList = item.appList; 
     var uuid= item.uuid; 
     db.collection('app_categories').find({schema_name:{$in: appList}}).toArray(function (err, result) { 
      if (err) throw err; 
      var catCount = _.countBy(result, function (obj) { 
       return obj.category; 
      }) 
      catObj['_id'] = uuid; 
      catObj['total_app_num'] = result.length; 
      catObj['app_breakdown'] = catCount; 
      db.collection('audiences').insert(catObj, function (err) { 
       if (err) console.log(err); 
      }); 
     }); 
    } 
    else { 
     // do something here after all items have been saved 
    } 
}); 

回答

1

這裏的關鍵是使用一些在執行「循環」操作時要遵守回調信號的東西。在這裏實現的.each()不會這樣做,所以你需要一個「異步」循環控制,這將表示每個循環已經迭代並完成,並且在回調中有自己的回調。

如果您的基礎MongoDB驅動程序至少爲版本2,則有一個.forEach(),它有一個回調,當迴路完成時會調用該回調。這比.each()好,但它不能解決內部「異步」操作已完成的問題。

所以更好的方法是使用由.find()返回的stream interface,這是允許更多的流量控制。有用於向後兼容性.stream()方法,但現代司機將只是默認情況下返回接口:

var stream = db.collection('user_apps').find({}); 

stream.on("err",function(err){ 
    throw(err); 
}); 

stream.on("data",function(item) { 
    stream.pause();     // pause processing of stream 
    var appList = item.appList; 
    var uuid= item.uuid; 
    db.collection('app_categories').find({schema_name:{ "$in": appList}}).toArray(function (err, result) { 
     if (err) throw err; 
     var catCount = _.countBy(result, function (obj) { 
      return obj.category; 
     }) 

     var catObj = {};  // always re-init 
     catObj['_id'] = uuid; 
     catObj['total_app_num'] = result.length; 
     catObj['app_breakdown'] = catCount; 
     db.collection('audiences').insert(catObj, function (err) { 
      if (err) console.log(err); 
      stream.resume();  // resume stream processing 
     }); 
    }); 
}); 

stream.on("end",function(){ 
    // stream complete and processing done 
}); 

流上的.pause()方法停止發射出進一步的活動,使每個對象的結果處理一次一個。當調用.insert()的回調時,將調用.resume()方法,表示該項目的處理已完成,並且可以進行新的調用以處理下一個項目。

當流完成時,所有事情都完成了,因此調用「結束」事件掛鉤來繼續您的代碼。

這樣一來,每個循環都用一個結束符表示,以移動到下一個迭代,並且在處理的完成結束時存在定義的「結束」事件。由於該控件位於.insert()回調的「內部」,因此這些操作也可以完成。

作爲一個附註,您可能會考慮在源集合中包含您的「類別」信息,因爲如果所有必需的數據都集中在一個集合中,您可能更有效地使用.aggregate()返回結果。

+0

這正是我一直在尋找的,謝謝。我不知道mongodb有一個流選項。如果可以,我會使用聚合,但不幸的是,我無法修改數據的存儲方式。 – Alistair

+0

只是一個簡短的說明,沒有什麼嚴重的,我認爲'最後'事件將在最後一個項目被保存之前被調用。 – Alistair

+0

@Alistair Nope。這就是爲什麼繼續在插入收到回調之後發生的原因。所以只要你總是在任何異步呼叫響應中恢復,那麼他們就完成了。 –