首页 > 解决方案 > 使嵌套的 mongodb 查询更快

问题描述

此函数在 getinitialprops 上触发,它等待它在渲染之前完成。有什么方法可以提高速度而不是等待这个长查询完成?

exports.getAppStats = (req, res, next) => {
  const startToday = moment(req.query.today).startOf('day');
  const endToday = moment(req.query.today).endOf('day');
  const startsevenDays = moment(req.query.today).subtract(7, 'd').startOf('day');
  const startThirtyDays = moment(req.query.today).subtract(30, 'd').startOf('day');
  const startYear = moment(req.query.today).subtract(365, 'd').startOf('day');

  const stats = {}
  Application.countDocuments({ dateTime: { $gte: startToday, $lte: endToday } })
    .then((result) => {
      stats.today = result
      Application.countDocuments({ dateTime: { $gte: startsevenDays, $lte: endToday } })
      .then((result) => {
        stats.sevenDays = result
        Application.countDocuments({ dateTime: { $gte: startThirtyDays, $lte: endToday } })
        .then((result) => {
          stats.thirtyDays = result
          Application.countDocuments({ dateTime: { $gte: startYear, $lte: endToday } })
          .then((result) => {
            stats.year = result
            return res.json(stats);
          }).catch(err => console.log(err))
        }).catch(err => console.log(err))
      }).catch(err => console.log(err))
    }).catch(err => console.log(err))
}

标签: javascriptnode.jsmongodbexpress

解决方案


在这里,您可以利用该Promise.all()函数并行运行所有查询,然后等待所有查询完成,如下所示:

exports.getAppStats = (req, res, next) => {
  const startToday = moment(req.query.today).startOf('day');
  const endToday = moment(req.query.today).endOf('day');
  const startsevenDays = moment(req.query.today).subtract(7, 'd').startOf('day');
  const startThirtyDays = moment(req.query.today).subtract(30, 'd').startOf('day');
  const startYear = moment(req.query.today).subtract(365, 'd').startOf('day');

  const stats = {}
  // get promises for each query
  let today = Application.countDocuments({ dateTime: { $gte: startToday, $lte: endToday } });
  let sevenDays = Application.countDocuments({ dateTime: { $gte: startsevenDays, $lte: endToday } });
  let thirtyDays = Application.countDocuments({ dateTime: { $gte: startThirtyDays, $lte: endToday } });
  let year = Application.countDocuments({ dateTime: { $gte: startYear, $lte: endToday } });
  // wait until all promises have been resolved, then set stats & send response
  Promise.all([today, sevenDays, thirtyDays, year]).then(([todayData, sevenDaysData, thirtyDaysData, yearData]) => {
    stats = {
      today: todayData,
      sevenDays: sevenDaysData,
      thirtyDays: thirtyDaysData,
      year: yearData
    }
    res.status(200).json({data: stats});
  }, (err) => {
    console.log(err);
    // next(err);
    // res.status(500).json({ message: "Something went wrong..." });
  });
}

或者,您可以使用async/await关键字来完全避免回调。虽然它需要try/catch处理错误。老实说,这没有什么区别,这纯粹是偏好。

// note this is now an async function
exports.getAppStats = async (req, res, next) => {
  const startToday = moment(req.query.today).startOf('day');
  const endToday = moment(req.query.today).endOf('day');
  const startsevenDays = moment(req.query.today).subtract(7, 'd').startOf('day');
  const startThirtyDays = moment(req.query.today).subtract(30, 'd').startOf('day');
  const startYear = moment(req.query.today).subtract(365, 'd').startOf('day');

  // get promises for each query
  let today = Application.countDocuments({ dateTime: { $gte: startToday, $lte: endToday } });
  let sevenDays = Application.countDocuments({ dateTime: { $gte: startsevenDays, $lte: endToday } });
  let thirtyDays = Application.countDocuments({ dateTime: { $gte: startThirtyDays, $lte: endToday } });
  let year = Application.countDocuments({ dateTime: { $gte: startYear, $lte: endToday } });
  try {
    // wait until all promises have been resolved, then set stats & send response
    // await Promise.all instead of using callbacks
    let [todayData, sevenDaysData, thirtyDaysData, yearData] = await Promise.all(
      [today, sevenDays, thirtyDays, year]
    );
    let stats = {
      today: todayData,
      sevenDays: sevenDaysData,
      thirtyDays: thirtyDaysData,
      year: yearData
    }
    res.status(200).json({data: stats});
  } catch(err) {
    console.log(err);
    // next(err);
    // res.status(500).json({ message: "Something went wrong..." });
  }
}

推荐阅读