【发布时间】:2019-09-16 19:47:51
【问题描述】:
前端代码包含一个名称列表,每个名称旁边都有复选框。目标是向所有被检查的姓名发送电子邮件。单击提交按钮时,会向我的后端发送一组 ID(针对每个用户)。
后端代码查询数据库(mongo 使用 mongoose odm)并找到用户。我需要在后端完成一些任务:
- 使用提供的 ID 数组查找用户
- 创建并向每个用户发送电子邮件
- 如果电子邮件发送成功,请更新数据库中用于发送电子邮件的文档字段
- 如果邮件失败,将用户名发回前端,通知“发件人”邮件尝试失败。
我在这段代码上工作的时间比我想承认的要长...这是我目前所拥有的(我担心后端代码):
exports.sendEmailToUsers = function (req, res, next) {
mongoose.model('SpendingReport').find({ _id: { $in: req.body.recipientIds } }).populate('report user')
.find({ 'report.emailedReport': { $exists: false } }) // this needs to be refined for dev, new reports will have an emailedGradePost property
.then(spendingReports => {
return Bluebird.map(spendingReports, spendingReport => {
const email = new Email({ email: spendingReport.user.email, name: spendingReport.user.fullName }, {})
return email.send()
.then(() => {
spendingReport.report.update({ emailedReport: new Date() })
// I don't need anything returned if it is successful, this feels weird though, map doesn't
// seem like the correct function to use.
// return {spendingReport.report.emailedGradePost}
})
.catch(e => {
// I am catching each email's error so I know which email failed
return { error: e, user: spendingReport.user.fullName }
});
});
})
.then(unsuccessfulAttempts => {
// the array has the error obect from the .catch and also undefined values for the successful attempts
console.log(unsuccessfulAttempts);
})
.then(() => {
res.sendStatus(200); // filler status for now
})
.catch(e => {
console.log(e);
});
};
这是我的问题:
- 我正在使用
Bluebird.map,这感觉就像代码的味道。理论上,我可以在包含来自数据库的一组文档的spendingReports数组上使用.map,并使用来自每个spendingReport的信息创建一封电子邮件。问题是,当我将电子邮件返回到承诺链中的下一个.then()时,我将无法访问spendingReport对象,例如
exports.sendEmailToUsers = function (req, res, next) {
mongoose.model('SpendingReport').find({ _id: { $in: req.body.recipientIds } }).populate('report user')
.find({ 'report.emailedReport': { $exists: false } }) // this needs to be refined for dev, new reports will have an emailedGradePost property
.then(spendingReports => {
return spendingReports.map(spendingReport => new Email({ email: spendingReport.user.email, name: spendingReport.user.fullName }, {}));
// {email: email, spendingReport: spendingReport} I might need this format instead, referenect the note
// in the next promise chain.
})
.then(emails => {
return Bluebird.map(emails, email => {
email.send()
.then(() => {
// Note: I lost access to "spendingReport", I would need to pass this object
// with each email object {email: email, spendingReport: spendingReport}
spendingReport.report.update({ emailedReport: new Date() })
.catch(e => {
return { error: e, user: spendingReport.user.fullName };
})
})
})
})
.then(unsuccessfulAttempts => {
console.log(unsuccessfulAttempts);
})
.then(() => {
res.sendStatus(200); // filler status for now
})
.catch(e => {
console.log(e);
});
};
-
我有一个嵌套的承诺链(在
李>Bluebird.map内,发送电子邮件,然后将其保存到成功的数据库中)。我知道嵌套承诺是一种反模式。减轻嵌套承诺的唯一方法是在每个.then中传递与每封电子邮件关联的文档对象,与在Bluebird.map中仅具有嵌套承诺链相比,这感觉更像是一种负担 当电子邮件成功并成功保存时,我不知道在
Bluebird.map中返回什么。现在我不返回任何东西,所以undefined被返回。理想情况下,我可以并行发送所有电子邮件,例如
Promise.all([email.send(), email.send(), email.send()]),但是,这使得将电子邮件成功保存到数据库更具挑战性(我需要再次访问spendingReports再次文档并更新report,这感觉就像很多查询)。
【问题讨论】:
-
您需要返回
spendingReport.report.update承诺或其中的then()将立即解决
标签: javascript mongodb promise