2017-09-22 54 views
0

我的數據庫中有幾百個文檔。模式很簡單:多個查詢以不可預知的排序結果結束

var firmsSchema = mongoose.Schema({ 
    name: String, 
    sections: [String], 
}); 

我想查詢文件和遍歷:

{{#each sections}} 
    {{sectionName}} 
    {{#each firms}} 
    {{firmName}} 
    {{/each}} 
{{/each}} 

簡單:

const SECTIONS = ['name_one', 'name_two', 'name_three']; 
const UNSORTED_SECTION_NAME = 'unsorted'; 

router.get('/', function(req, res, next) { 
    var showFirms = function showSection (i, acc) { 
    if (i < 0) return; 
    let query = SECTIONS[i] ? {sections: SECTIONS[i]} : {sections: {$nin: SECTIONS}}; 
    let key = SECTIONS[i] || UNSORTED_SECTION_NAME; 
    Firms.find(query). 
    then((result) => { 
     acc.push({ 
     section: key, 
     firms: result, 
     }); 
     if (i === SECTIONS.length) { 
     acc = acc.sort((a, b) => (a.section > b.section)); 
     res.render('template', { 
      sections: acc, 
     }); 
     } 
    }). 
    then(showSection (i - 1, acc)); 
    } 
    showFirms(SECTIONS.length, []); 
}; 

工作正常。除了它返回acc隨機和不可預知的排序。我的意思是'name_two'部分可以按照'name_one'或反之亦然。

我認爲.sort()在承諾的末尾鏈將是一個銀色的子彈在這裏,並解決所有的異步問題,但它沒有。

當然,我可以排序acc與把手幫手後,我把它傳遞給我的模板,但它是如此荒謬的奇怪,我不能排序後,我的showFirms功能已完成所有查詢。

你能給我一些建議嗎?

+0

不應該排序成爲您對mongodb的請求的一部分嗎?如果返回值不可預知,我看不到如何處理查詢以外的排序 – Icepickle

+0

您正在字符串之間進行比較。例如:'name_one'>'name_two'。這是錯的 –

+0

這裏的問題是我運行多個請求('showSection'是一個遞歸函數),然後我收集累加器'acc'的所有結果,然後傳遞給我的模板。如果排序是每個請求的一部分,它只需對每個響應中的元素進行排序。這不是我想要實現的。 – ivanzolotov

回答

2

看看你的代碼重製。我們不是一個一個地獲取數據,而是要在同一時間(異步)獲取它們,然後處理返回。

如果您有任何問題,我在這裏,這段代碼沒有經過測試,所以給我一個反饋。這是您如何更改代碼的示例。

const showFirms = function showSection() { 
    return new Promise((resolve, reject) => { 
    // Get the keys for the queries 
    const keys = SECTIONS.map(x => x || UNSORTED_SECTION_NAME); 

    // For each sections we gonna call a find request 
    const promises = SECTIONS.map((x, xi) => { 
     const query = x ? { 
     sections: x, 
     } : { 
     sections: { 
      $nin: SECTIONS, 
     }, 
     }; 

     const key = keys[xi]; 

     return Firms.find(query); 
    }); 

    // Resolve all promises 
    Promise.all(promises) 
     .then((rets) => { 
     // Use the finds results to build an acc array 
     const accs = rets.map((x, xi) => ({ 
      section: keys[xi], 
      firms: x, 
     })); 

     // Change the sort -> ;) #comments 
     const sortedAccs = accs.sort((a, b) => (a.section > b.section)); 

     resolve(sortedAccs); 
     }) 
     .catch(reject); 
    }); 
}; 

如何使用它

showFirms() 
    .then(accs => res.render('template', { 
    sections: accs, 
    })) 
    .catch(err => console.log(`I have an error ${err.toString()}`)); 
+1

棒極了!對於我來說,我有點難以理解,因爲我是EcmaScript中承諾的新事物,但它以可預測的方式返回我需要的一切。爲了更好地理解這裏發生的事情,我們將嘗試作爲解釋者多次工作。另外,正如我所看到的,這個解決方案在'SECTIONS'數組中查詢預定義的鍵,並且不會在部分字段中返回沒有或帶有其他值的文檔。將嘗試做一些改進。 – ivanzolotov

+0

而且我還不明白我最初的代碼有什麼問題。我不相信魔法。 – ivanzolotov

+1

您最初的代碼中的問題是,您正在向第一次查找調用後要呈現的頁面發送一個指向「acc」數組的指針。然後異步地*隨機*,另一個查找得到執行並填充'acc'對象。當你使用'acc'的時候,純粹的隨機*有多少請求完成並被推送到'acc'。 –

0

基於了GrégoryNEUTS優秀的解決方案。我簡化了一些事情,並使「其他部分案例」起​​作用。我甚至退出了​​排序功能。最終的結果按照在最初的SECTIONS數組中聲明的部分順序返回,所以現在我可以重新排序以控制輸出。

const showFirms = function() { 
    return new Promise ((resolve, reject) => { 

    const extendedSections = SECTIONS.slice(); 
    extendedSections.push(UNSORTED_SECTION_NAME); 

    const promises = extendedSections.map((section) => { 
     const unsortedCase = section === UNSORTED_SECTION_NAME; 
     const query = unsortedCase ? {sections: {$nin: SECTIONS}} : {sections: section}; 
     return Firms.find(query); 
    }) 

    Promise.all(promises) 
     .then((allResponces) => { 
     const sectionsData = allResponces.map((response, i) => ({ 
      section: extendedSections[i], 
      firms: response, 
     })); 
     resolve(sectionsData); 
     }) 
     .catch(reject); 
    }); 
};