多个查询以不可预测的排序结果结束

时间:2017-09-22 08:54:05

标签: javascript node.js mongodb express mongoose

我的数据库中有几百个文档。架构非常简单:

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进行排序,但是在我{{1}完成所有查询之后我无法对它进行排序是非常奇怪的。功能。

你能给我一些建议吗?

2 个答案:

答案 0 :(得分: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 :(得分: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);
  });
};