Pg-promise: 返回查询结果的正确方式

4

我想使用pg-promise来检查用户名是否已被使用。

我使用以下查询:

this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username);

我在尝试将这个查询封装在一个函数中,该函数仅在用户名存在时返回true,否则返回false。
类似于:
```javascript function checkUsername(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
}

然而,如果条件在查询完成之前被评估,则会导致未定义变量。

返回查询结果的正确方法是什么?

编辑:外部调用程序执行多个异步检查,并返回用户是否有效:

function signUp(username, email, ...){
  // perform username existence check existsUser(username)

  // perform email existence check existsEmail(username)

  // ...

  // if everything OK, put user in DB
}

您似乎在existsUsername函数中忘记了return语句。 - Alejandro
2个回答

6

最简单的方法:

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))


如果你有三个独立的函数(checkUserNamecheckEmailcheckWhateverElse),想要执行它们所有,下面是最好的方法:

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-任务上下文执行查询,以便共享连接。


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


1
使用 Promise.all([checkUserName(), checkEmail(), checkWhateverElse()]).then( arrayOfChecksResults => // 检查数组是否正常,然后保存用户 ) - Alejandro
1
除了 Promise.all 之外,还有其他方法来管理一堆 Promise,你可以检查哪种方法更适合你。 - Alejandro
1
这正是我正在寻找的!谢谢! - Kathandrax
1
请注意,http://bluebirdjs.com/docs/getting-started.html 中的Bluebird Promise具有更好的性能。 - Alejandro
2
你不应该在数据库方法中使用Promise.all,因为它们最终会针对单独的连接执行,这对性能不利。请参阅链接查询。相反,你应该使用一个带有批处理的任务。 - vitaly-t
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接