我正在尝试使用猫鼬查询我的mongodb集合,但未呈现结果。我想我知道为什么,因为有些东西,异步/等待/承诺,但没有任何效果。基本上,我需要2个查询,其中一个要拉出所请求的链接中提到的对象(workflowID),它本身具有多个“步骤”,这些步骤在对象ID的数组中引用。它们不会被推送到范围变量(workflowStepCombined)。如果我将结果记录在forEach中,该查询将按预期工作,那么我将得到预期的结果。就像我提到的那样,我认为问题在于应用程序没有在等待结果,我已经阅读了关于Promise的猫鼬文档,并实施了我认为的解决方案,但是整天重构后却没有任何进展。
app.get("/new/:workflowID", function (req, res) {
if (req.isAuthenticated()) {
const workflowID = req.params.workflowID;
//define array to push recombined steps to
let workflowStepCombined = [];
Workflow.findOne({ workflowName: workflowID }, function (err,foundWorkflow) {
const stepsArray = foundWorkflow.workflowStepArray;
//once workflow found, start pulling from step collection the listed IDs
stepsArray.forEach(function (step) {
Steps.findOne({ _id: step }, (err, foundStep) => {
//push to array that was definedin first part
workflowStepCombined.push(foundStep);
});
});
//render it all together
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
});
} else {
res.redirect("/");
}
});
并且我也尝试使用.then,因为从我有限的理解出发,我需要让它等待查询结果之后再移至下一行代码。但这也不起作用,它的行为相同。
app.get("/new/:workflowID", function (req, res) {
if (req.isAuthenticated()) {
//allows for dynamic link creation
const workflowID = req.params.workflowID;
const stepsArray = [];
//define array to push recombined steps to
let workflowStepCombined = [];
//find workflow with name from link
Workflow.findOne({ workflowName: workflowID }).then(foundWorkflow => {
stepsArray.push(foundWorkflow.workflowStepArray);
})
console.log(stepsArray)
//once workflow found, start pulling from step collection the listed IDs
stepsArray.forEach(function (step) {
Steps.findOne({ _id: step }).then(foundStep => {
workflowStepCombined.push(foundStep);
console.log(foundStep);
});
});
//render it all together
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
答案 0 :(得分:0)
forEach函数不是异步的,因此您在获取步骤结果之前调用res.render。您应该使用Promise.all函数
Promise.all(stepsArray.map(step => Steps.findOne({ _id: step })))
.then(workflowStepCombined => {
return res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
})
我建议您使用异步/等待方法,而不要使用回调
app.get("/new/:workflowID", async (req, res) => {
if (req.isAuthenticated()) {
const workflowID = req.params.workflowID;
//define array to push recombined steps to
let workflowStepCombined = [];
const workflow = await Workflow.findOne({ workflowName: workflowID });
const stepsArray = foundWorkflow.workflowStepArray;
const workflowSteps = await Steps.find({_id: {$in: stepsArray}}) //https://docs.mongodb.com/manual/reference/operator/query/in/ and you could use sort here if needed - https://mongoosejs.com/docs/api.html#model_Model.find
//render it all together
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowSteps,
});
} else {
res.redirect("/");
}
});
答案 1 :(得分:0)
是的,您说对了,问题出在服务器发送响应之前,诺言没有得到解决。这部分代码是罪魁祸首:
stepsArray.forEach(function (step) {
Steps.findOne({ _id: step }, (err, foundStep) => {
//push to array that was definedin first part
workflowStepCombined.push(foundStep);
});
});
Array.forEach
在异步回调方面比较棘手,在您的情况下,您希望每个循环在下一个循环之前执行并解决,以便在循环结束时,所有findOne
查询的结果将位于workflowStepCombined
数组中,但是情况并非如此,您可以签出this article for why。
直接的解决方法是像这样使用Promise.all
:
Promise.all(stepsArray.map(stepId => Steps.findOne({_id: stepId})))
.then(workflowStepCombined => {
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
})
但是,由于sepsArray
是工作流程步骤_id
的数组,因此您可以使用单个查找查询,而不必循环执行多个查询。像这样:
Steps.find({ _id: { $in: stepsArray } })
这应该返回包含stepsArray
中标识的所有步骤对象的数组,因此不需要循环和推送。将此与上一个查询结合起来,端点应该是这样的:
app.get("/new/:workflowID", function (req, res) {
if (req.isAuthenticated()) {
const workflowID = req.params.workflowID;
Workflow.findOne({ workflowName: workflowID }, function (err,foundWorkflow) {
const stepsArray = foundWorkflow.workflowStepArray;
Steps.find({ _id: { $in: stepsArray } }, function(error, workflowStepCombined) {
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
})
});
} else {
res.redirect("/");
}
});
记住要捕捉并处理可能的错误