pg-promise:返回查询结果的正确方法
Posted
技术标签:
【中文标题】pg-promise:返回查询结果的正确方法【英文标题】:Pg-promise: proper way of returning result of query 【发布时间】:2018-10-14 01:47:07 【问题描述】:我想使用pg-promise
检查用户名是否已在使用中。
我使用以下查询:
this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username);
我试图将此查询封装在一个函数中,如果用户名存在则返回 true,否则返回 false。
类似:
existsUsername(username)
this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username)
.then(data =>
if(data.exists == true)
return true;
else
return false;
);
我可以像这样简单地使用:
if(db.users.existsUsername(username))
// this username is already taken
但是 if 条件在查询完成之前被评估,导致一个未定义的变量。
返回查询结果的正确方法是什么?
编辑:外部调用者执行多个异步检查并返回用户是否有效:
function signUp(username, email, ...)
// perform username existence check existsUser(username)
// perform email existence check existsEmail(username)
// ...
// if everything OK, put user in DB
【问题讨论】:
U 似乎忘记在 existsUsername 中返回 【参考方案1】:您不能以同步方式使用异步操作,您还需要重写检查用户是否以异步方式存在的代码。即:
// returns a promise
function existsUsername(username)
return this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username);
然后在应用程序中以类似的方式使用它
db.users.existsUsername(username)
.then( data =>
data.exists ? handleUserExistsAsync() : handleUserNotExistsAsync();
)
.catch( err =>
// some err occurs, db fail or something
// however, you can catch it in an upper level
);
编辑:将Promise.all 用于多项任务,可能会出现性能和连接问题(如 Vitaly 所述)。
最好在db.task里面使用db.batch
【讨论】:
感谢您的回答。但是由于我有多个这样的查询(existsUsername、existsEmail 等),我怎么知道所有异步操作都已完成并且我可以继续执行调用者的 return 语句? 是的,使用 Promise.all([checkUserName(), checkEmail(), checkWhateverElse()]).then( arrayOfChecksResults => // 检查数组是否正常,并保存用户) 除了 Promise.all 还有其他方法来管理一堆 Promise,你可以检查哪一个更适合你 这正是我想要的!谢谢! 您永远不应该将Promise.all
与数据库方法一起使用,因为它们最终都会针对单独的连接执行,这对性能不利。见Chaining Queries。相反,您应该使用带有batch
的任务。【参考方案2】:
最简单的方法:
existsUsername(username)
return this.db.oneOrNone('SELECT * FROM users WHERE username = $1 LIMIT 1', username, a => !!a);
然后使用它:
db.users.existsUsername(username)
.then(exists =>
// exists - boolean
)
.catch(error =>
);
你不能做if(db.users.existsUsername(username))
之类的事情,这会将同步代码与异步代码混为一谈。但是,如果您可以使用 ES7 语法,您可以使用 if(await db.users.existsUsername(username))
。
如果你有三个这样的独立函数(checkUserName
、checkEmail
、checkWhateverElse
),并且想要全部执行,那么最好的方法是:
db.task(t =>
return t.batch([checkUserName(t), checkEmail(t), checkWhateverElse(t)]);
)
.then(data =>
// data = result of the batch operation;
)
.catch(error =>
// error
);
与 ES7 语法相同:
db.task(async t =>
const a = await checkUserName(t);
const b = await checkEmail(t);
const c = await checkWhateverElse(t);
return a, b, c;
)
.then(data =>
// data = a, b, c object;
)
.catch(error =>
// error
);
注意:每个函数都应针对t
- 任务上下文执行查询,以便共享连接。
【讨论】:
以上是关于pg-promise:返回查询结果的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
pg-promise:在事务中的下一个查询中使用一个查询的结果