Postgresql pg promise-不解析多个查询
我正在创建一个群发邮件程序,允许公司向包含X个订户的特定计划发送电子邮件模板 但是,在使用pg PROMITE时,我无法理解如何循环遍历包含一个或多个唯一计划名称的数组,这些名称将用作后续查询的查询参数,以收集单个结果数组。在express发回指定的错误消息之前,无法解析后续查询 例如:Postgresql pg promise-不解析多个查询,postgresql,express,pg-promise,Postgresql,Express,Pg Promise,我正在创建一个群发邮件程序,允许公司向包含X个订户的特定计划发送电子邮件模板 但是,在使用pg PROMITE时,我无法理解如何循环遍历包含一个或多个唯一计划名称的数组,这些名称将用作后续查询的查询参数,以收集单个结果数组。在express发回指定的错误消息之前,无法解析后续查询 例如: const selectedTemplate = await db.oneOrNone("SELECT * FROM templates WHERE userid=$1 and uniqueTemplateNa
const selectedTemplate = await db.oneOrNone("SELECT * FROM templates WHERE userid=$1 and uniqueTemplateName=$2", [req.session.id, req.body.uniquetemplatename])
返回一个JSON对象
{ ...
plans : [ 'Unique Plan 1', 'Unique Plan 2', 'Unique Plan 3'...],
...
}
然后我想通过这个plans数组来收集一些订户电子邮件。由于selectedTemplate的plans数组可以包含一个或多个唯一的计划,因此我试图找出如何使此查询工作:
let subscriberEmails = [];
await each(selectedTemplate.plans, async plan => {
const emails = await db.any("SELECT email FROM subscribers WHERE userid=$1 AND planName=$2", [req.session.id, plan])
each(emails, ({email}) => subscriberEmails.push(email))
console.log('Found emails: ', subscriberEmails);
})
console.log('Selected emails: ', subscriberEmails);
res.status(500).json({ message: "Route not configured yet" })
我遇到的问题是Express没有等待pg承诺的解决。因此,它会触发“我的500服务器路由尚未配置”消息,然后解析查询:
14:48:33 SELECT * FROM templates WHERE userid='12345' and uniqueTemplateName='example-unique-template'
selectedTemplate: anonymous {
id: '84efa448-b149-11e8-a7fd-3b9e4e9e5ece',
key: 9,
userid: '12345',
status: 'active',
fromsender: 'example@helpdesk.com',
subject: 'Thank you for using our services!',
templatename: 'Example Unique Template',
uniquetemplatename: 'example-unique-template',
message: '<h3>This is a test!</h3>',
plans: [ 'Unique Plan 1', 'Unique Plan 2' ]
}
Selected emails: []
POST /api/messages/create 500 28 - 34.125 ms
14:48:33 SELECT email FROM subscribers WHERE userid='12345' AND planName='Unique Plan 1'
Found emails: [
'betatester19@example.com',
'betatester20@example.com',
'betatester21@example.com'
]
14:48:34 SELECT email FROM subscribers WHERE userid='12345' AND planName='Unique Plan 2'
Found emails: [
'betatester19@example.com',
'betatester20@example.com',
'betatester21@example.com',
'betatester1@example.com',
'betatester2@example.com',
'betatester3@example.com',
'betatester4@example.com',
'betatester5@example.com',
'betatester6@example.com',
'betatester7@example.com',
'betatester8@example.com',
'betatester9@example.com',
'betatester10@example.com',
'betatester11@example.com',
'betatester12@example.com',
'betatester13@example.com',
'betatester14@example.com',
'betatester15@example.com',
'betatester16@example.com',
'betatester17@example.com',
'betatester18@example.com'
]
大大简化的数据库结构:
├── Template
│ └── Plans (references an array of unique plan name(s))
|
|── Plan
| └── PlanName (unique plan name)
|
│── Subscriber
| └── PlanName (references a single unique plan name)
| └── Email (unique email)
我尝试使用db.task,但在Express发回消息之前,这些查询仍然没有解决。找到了问题所在。以防万一,其他人会遇到这样的困境:像map和each这样的函数不处理async/await。相反,他们只是返回一个待定的承诺。因此,您需要使用类似的库,它实现集合下基于承诺的each/map/etc函数 上述问题的解决方案:
try {
await db.task('create-message', async t => {
const selectedTemplate = await t.oneOrNone(findTemplateByName, [req.session.id, uniquetemplatename])
if (!selectedTemplate) return sendError(unableToLocate('template'), res, done);
const { fromsender, subject, message, plans, templatename } = selectedTemplate;
let subscriberEmails = [];
await Promise.each(plans, async plan => {
const emails = await t.any(getAllEmailsByPlan, [req.session.id, plan]);
each(emails, ({email}) => subscriberEmails.push(email));
})
if (isEmpty(subscriberEmails)) return sendError(unableToLocate('subscribers in the selected plan(s)'), res, done);
const msg = {
to: subscriberEmails,
from: fromsender,
replyTo: fromsender,
subject: subject,
html: message
};
await mailer.sendMultiple(msg);
await t.none(createMessageTransaction, [req.session.id, templatename, fromsender, subject, currentDate, plans]);
await t.none(createNotification, [req.session.id, 'mail_outline', `The following template: ${templatename} has been sent out to the subscibers in the following ${plans.length > 1 ? "plans" : "plan"}: ${plans}.`, date]);
return res.status(201).send(null);
})
} catch (err) { return sendError(err, res, done); }
这仍然是一个糟糕的解决方案,请参见。@vitaly-t更新了答案。这是更好的解决方案吗?要将所有查询包装到单个任务中?谢谢。现在看起来好多了;你可以让它变得更简单。你真的不需要等待承诺。每一个,一个简单的for循环也会在那里工作,这意味着你不需要把Bluebird带进它,尽管它通常是一个很好的库来使用;然后在任务上,使其非异步;
try {
await db.task('create-message', async t => {
const selectedTemplate = await t.oneOrNone(findTemplateByName, [req.session.id, uniquetemplatename])
if (!selectedTemplate) return sendError(unableToLocate('template'), res, done);
const { fromsender, subject, message, plans, templatename } = selectedTemplate;
let subscriberEmails = [];
await Promise.each(plans, async plan => {
const emails = await t.any(getAllEmailsByPlan, [req.session.id, plan]);
each(emails, ({email}) => subscriberEmails.push(email));
})
if (isEmpty(subscriberEmails)) return sendError(unableToLocate('subscribers in the selected plan(s)'), res, done);
const msg = {
to: subscriberEmails,
from: fromsender,
replyTo: fromsender,
subject: subject,
html: message
};
await mailer.sendMultiple(msg);
await t.none(createMessageTransaction, [req.session.id, templatename, fromsender, subject, currentDate, plans]);
await t.none(createNotification, [req.session.id, 'mail_outline', `The following template: ${templatename} has been sent out to the subscibers in the following ${plans.length > 1 ? "plans" : "plan"}: ${plans}.`, date]);
return res.status(201).send(null);
})
} catch (err) { return sendError(err, res, done); }