异步查询Node.js中的多个MongoDB集合

时间:2018-03-10 19:00:35

标签: node.js mongodb express asynchronous post

我需要为同一请求class获取两个不同的MongoDB集合(Deque<Action> undoStack = new ArrayDeque<>(); Deque<Action> redoStack = new ArrayDeque<>(); public void doAction(Action action) { redoStack.clear(); // new action prevents redo of previous undo undoStack.push(action); } public Action undoAction() { Action action = undoStack.pop(); // Throws exception if stack is empty redoStack.push(action); return action; } public Action redoAction() { Action action = redoStack.pop(); // Throws exception if stack is empty undoStack.push(action); return action; } db.stats)。

现在,在下面的代码中,我将查询嵌套在回调函数中。

db.tables

此代码有效,但有些事情似乎不对。所以我的问题是:

如何避免这种嵌套结构?因为它不仅看起来很丑,而且在处理这些请求时,客户端没有响应,这很糟糕。

2 个答案:

答案 0 :(得分:2)

您现在拥有的内容在JavaScript中被称为回调地狱。这是Promises派上用场的地方。

以下是您可以做的事情:

router.post('/', (req, res) => {
  let season = String(req.body.year);
  var queries = [
    db.stats.findOne({ Year: season }),
    db.tables.findOne({ Year: season })
  ];

  Promise.all(queries)
  .then(results => {
    if (!results[0]) {
      console.log("Error in Stats");
      return; // bad response. a better way is to return status 500 here
    } else if (!results[1]) {
      console.log("Error in Tables");
      return; // bad response. a better way is to return status 500 here
    }
    let resultData = getResult(results[0]);
    let resultTable = getTable(results[1]);

    res.render('index.html', { data: {
      result : resultData,
      message: "Working"
    } });
  })
  .catch(err => {
    console.log("Error in getting queries", err);
    // bad response. a better way is to return status 500 here
  });
});

看起来您正在使用Mongoose作为您的ODM来访问您的mongo数据库。如果您未将函数作为第二个参数传入,则函数调用返回的值(例如db.stats.findOne({ Year: season }))将是Promise。我们将所有这些未解决的Promise放在一个数组中,并调用Promise.all来解决它们。通过使用Promise.all,您将等待所有数据库查询执行,然后再继续呈现index.html视图。在这种情况下,数据库函数调用的结果将按results数组的顺序存储在queries数组中。

此外,除了res.status(500).send("A descriptive error message here")来电之外,每当服务器端出现错误时,我建议您执行console.log之类的操作。

以上将解决您的嵌套结构问题,但后一个问题仍然存在(即客户端在处理这些请求时没有响应)。为了解决这个问题,您需要首先确定您的瓶颈。什么函数调用占用了大部分时间?由于您使用的是findOne,因此除非您的服务器与数据库之间的连接存在延迟问题,否则我认为这不会成为瓶颈。

我将假设POST请求不是通过AJAX完成的,因为你有res.render,所以这个问题不应该由任何客户端代码引起。我怀疑getResultgetTable(或两者)中的任何一个占用了相当多的时间,考虑到它会导致客户端无响应。查询数据库时数据的大小是多少?如果它的大小太大而需要花费大量的时间来处理,我建议改变请求的方式。您可以在前端使用AJAX向后端发出POST请求,然后将该响应作为JSON对象返回。这样,浏览器上的页面就不需要重新加载,您将获得更好的用户体验。

答案 1 :(得分:1)

如果您不发送回调,mongodb驱动程序会返回一个承诺,因此您可以使用async await

&#13;
&#13;
router.post('/', async(req, res) => {
    let season = String(req.body.year);
    let resultData, resultTable;
    try {
        const [data1,data2] = await Promise.all([
            db.stats.findOne({Year: season}),
            db.tables.findOne({Year: season})
        ]);
        if (data1 && data2) {
            resultData = getResult(data1);
            resultTable = getTable(data2);
           return res.render('index.html', {
                data: {
                    result: resultData,
                    message: "Working"
                }
            });
        }
        res.send('error');
        console.log("Error");
    } catch (err) {
        res.send('error');
        console.log("Error");
    }

});
&#13;
&#13;
&#13;