Javascript 如何使用Express从一个端点发送多个查询?
我试图多次查询我的数据库,并构造一个对象,将数据库中的每个响应存储在一个字段中。这是我的密码:Javascript 如何使用Express从一个端点发送多个查询?,javascript,node.js,rest,express,Javascript,Node.js,Rest,Express,我试图多次查询我的数据库,并构造一个对象,将数据库中的每个响应存储在一个字段中。这是我的密码: router.post('/search', (req, res) => { var collection = db.get().collection('styles') var data = []; collection.distinct('make.name', (err, docs) => { data.push({'make': docs })
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);
});
});
见:
但这可能仍然不是最方便的方法
ES2017async
/wait
如果你有30个电话要打,最灵活的方法是:
Promise.all()
// in sequence:
var make = await collection.distinct('make.name');
var model = await collection.distinct('model');
// use 'make' and 'model'
或:
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
关键字创建的函数中使用它。有关详细信息,请参阅:
async
和wait
的地方,可以使用Babel:
co
或Bluebird协同程序:
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);
});
});
见:
但这可能仍然不是最方便的方法
ES2017async
/wait
如果你有30个电话要打,最灵活的方法是:
Promise.all()
// in sequence:
var make = await collection.distinct('make.name');
var model = await collection.distinct('model');
// use 'make' and 'model'
或:
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
关键字创建的函数中使用它。有关详细信息,请参阅:
async
和wait
的地方,可以使用Babel:
co
或Bluebird协同程序:
- 你可以通过承诺来实现
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请求并使用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
});
你可以通过承诺来做到
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请求并使用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
});
你应该使用承诺。@SLaks,我理解承诺的概念,但我从来没有实践过。如果您可以发布代码示例,我会将您的答案标记为正确。您应该使用承诺。@SLaks,我理解承诺的概念,但我从未应用过承诺。如果你能发布一个代码示例,我会把你的答案标记为正确的;它们不仅是有条件的,而且会有嵌套的噩梦。我欣赏你的方法,但是,它不够有效。我正在尝试为我的站点上可用的刻面搜索函数获取参数。@对于复杂代码,最灵活的解决方案是异步/等待或基于生成器的协同路由。看看我最新的答案。我有大约30个不同的电话要打;它们不仅是有条件的,而且会有嵌套的噩梦。我欣赏你的方法,但是,它不够有效。我正在尝试为我的站点上可用的刻面搜索函数获取参数。@对于复杂代码,最灵活的解决方案是异步/等待或基于生成器的协同路由。查看我的更新答案。您能解释结果[0]和结果[1]之间的差异吗?接下来是什么。。结果[2]。。。“n次呼叫的结果[n]?@Moshe确定。在
Promise.all
函数中有一个承诺数组。因此,在中,然后在Promise的中。所有处理程序都有一个参数数组,在每个Promise
输入数组中传递给resolve
回调函数,其顺序与它们在输入数组中的顺序相同,以便于澄清!你能解释一下结果[0]和结果[1]之间的区别吗?接下来是什么。。结果[2]。。。“n次呼叫的结果[n]?@Moshe确定。你有一个P的数组