2017-04-04 91 views
3

我目前解析由一個upserted到DB一個JS對象的列表upserting數據庫,大致是這樣使用的是Node.js:承諾與散裝

return promise.map(list, 
    return parseItem(item) 
     .then(upsertSingleItemToDB) 
    ).then(all finished!) 

的問題是,當列表大小變得非常大(〜3000個項目),並行解析所有項目的內存過於龐大。在promise庫中添加併發限制非常簡單,並且不會以這種方式耗盡內存(何時/保護)。

但我想優化db的upserts,因爲mongodb提供了一個bulkWrite函數。由於一次解析和批量寫入所有項目是不可能的,因此我需要將原始對象列表拆分爲更小的集合,這些集合使用promise並行解析,然後將該集合的結果數組傳遞給promisified bulkWrite。如果列表項目在剩下的集合中會重複。

我很難包裝我的頭如何可以構造更小的承諾集,以便我只做一組parseSomeItems-BulkUpsertThem(類似Promise.all([set1Bulk] [set2Bulk] ),其中set1Bulk是另一個並行解析器Promise的數組?),任何僞代碼的幫助將不勝感激(但我使用時,如果這有所作爲)。

回答

1

它可以是這個樣子,如果用貓鼬和底層的NodeJS-MongoDB的驅動程序:

const saveParsedItems = items => ItemCollection.collection.bulkWrite(// accessing underlying driver 
 
    items.map(item => ({ 
 
     updateOne: { 
 
      filter: {id: item.id}, // or any compound key that makes your items unique for upsertion 
 
      upsert: true, 
 
      update: {$set: item} // should be a key:value formatted object 
 
     } 
 
    })) 
 
); 
 

 

 
const parseAndSaveItems = (items, offset = 0, limit = 3000) => { // the algorithm for retrieving items in batches be anything you want, basically 
 
    const itemSet = items.slice(offset, limit); 
 
    
 
    return Promise.all(
 
    itemSet.map(parseItem) // parsing all your items first 
 
) 
 
    .then(saveParsedItems) 
 
    .then(() => { 
 
     const newOffset = offset + limit; 
 
     if (items.length >= newOffset) { 
 
     return parseAndSaveItemsSet(items, newOffset, limit); 
 
     } 
 
     
 
     return true; 
 
    }); 
 
}; 
 

 
return parseAndSaveItems(yourItems);

+1

啊,遞歸,當然!我的大腦在圈子裏跑來跑去試圖做出一些長長的承諾......感謝一大堆,這正是我期待的<3 – usagidon

1

第一個答案看起來完整。然而,這裏還有一些想到的其他想法。

作爲一種手段,您可以在下一次寫入操作執行之前,在寫入操作的回調中調用超時函數。這可以讓你的CPU和內存中斷呼叫。即使您在兩次調用之間添加一毫秒,如果您總共有3000個寫入對象,也只會增加3秒。

或者您可以將您的insertObjects數組分段,並將它們發送到他們自己的批量寫入器。