繁体   English   中英

如何使用Express从一个端点发送多个查询?

[英]How do I send multiple queries from one endpoint with Express?

我试图多次查询数据库,并构造一个对象,该对象将数据库中的每个响应存储在一个字段中。 这是我的代码:

router.post('/search', (req, res) => {
    var collection = db.get().collection('styles')
    var data = [];

    collection.distinct('make.name', (err, docs) => {
      data.push({'make': docs });
    });

    collection.distinct('model', (function (err, docs) {
        data.push({'model': docs });
    }))

    res.send(data);
});

由于NodeJS / Express是异步的,因此无法正常运行。 如何重构此端点以进行多个数据库调用(来自同一集合)并返回包含该端点的对象?

有多种方法可以做到这一点:

嵌套回调

没有承诺,您可以嵌套回调:

router.post('/search', (req, res) => {
    var collection = db.get().collection('styles')
    var data = [];

    collection.distinct('make.name', (err, docs) => {
      if (err) {
        // ALWAYS HANDLE ERRORS!
      }
      data.push({'make': docs });
        collection.distinct('model', (function (err, docs) {
          if (err) {
            // ALWAYS HANDLE ERRORS!
          }
          data.push({'model': docs });
          res.send(data);
        }))
    });
});

这将是最简单的方法,但请注意,如果可以并行执行这两个请求,则效率不高。

async模块

您可以使用async模块:

router.post('/search', (req, res) => {
    var collection = db.get().collection('styles')
    var data = [];

    async.parallel({
      make: cb => collection.distinct('make.name', cb),
      model: cb => collection.distinct('model', cb),
    }, (err, responses) => {
      if (err) {
        // ALWAYS HANDLE ERRORS!
      }
      data.push({'make': responses.make });
      data.push({'model': responses.model });
      res.send(data);
    });
});

参见: https : //caolan.github.io/async/docs.html#parallel

但这可能仍然不是最方便的方法。

ES2017 async / await

如果您要打30次电话,最灵活的方法是:

  1. 使用返回promise的函数,而不是使用回调的函数
  2. 如果可以或至少基于生成器的协程,请使用异步/等待
  3. 当逻辑需要按顺序运行时,等待承诺(或产量承诺)
  4. 使用Promise.all()可以并行执行的任何操作

使用异步/等待,您的代码可能如下所示:

    // in sequence:    
    var make = await collection.distinct('make.name');
    var model = await collection.distinct('model');
    // use 'make' and 'model'

要么:

    // in parallel:
    var array = await Promise.all([
      collection.distinct('make.name'),
      collection.distinct('model'),
    ]);
    // use array[0] and array[1]

async / await一大优势是错误处理:

try {
  var x = await asyncFunc1();
  var array = await Promise.all([asyncFunc2(x), asyncFunc3(x)]);
  var y = asyncFunc4(array);
  console.log(await asyncFunc5(y));
} catch (err) {
  // handle any error here
}

您只能在使用async关键字创建的函数中使用它。 有关更多信息,请参见:

有关浏览器的支持,请参阅:

有关Node的支持,请参见:

在您没有本地支持asyncawait ,可以使用Babel:

或使用稍有不同的语法,使用基于生成器的方法(例如co或Bluebird协程):

查看这些答案以获取更多信息:

您可以用Promises做到

router.post('/search', (req, res) => {
    var collection = db.get().collection('styles');
    // Create promise for "make.name" query
    let firstQuery = new Promise((resolve, reject) => {
        collection.distinct('make.name', (err, docs) => {
            if (!err) {
                resolve(docs);
            } else {
                reject(err);
            }
        });
    });
    // Create promise for "model" query
    let secondQuery = new Promise((resolve, reject) => {
        collection.distinct('model', (function (err, docs) {
            if (!err) {
                resolve(docs);
            } else {
                reject(err);
            }
        }))
    })
    // Run both queries at the same time and handle both resolve results or first reject
    Promise.all([firstQuery, secondQuery])
        .then((results) => {
            res.send({ "make.name": results[0], "model": results[1] });
        })
        .catch((err) => {
            // Catch error 
            res.send({});
        });
});

您也可以在回调函数中使用解构,例如:

Promise.all([firstQuery, secondQuery])
    .then(([makeName, model]) => res.send({ "make.name": makeName, model }))

UPD:例如,如果您有大量要请求的集合,则可以创建一个集合名称数组,将其映射为Promise.all来承诺请求并进行处理。

let collections = ["firstCollection", "secondCollection", "nCollection"];
let promises = collections.map((collectionName) => {
    return new Promise((resolve, reject) => {
        collection.distinct(collectionName, (err, docs) => {
            if (!err) {
                resolve(docs)
            } else {
                reject(err);
            }
        });
    })
});
Promise.all(promises)
    .then(results => {
        // Do what you want to do
    })
    .catch(error => {
        // or catch 
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM