javascript - 使用 Firebase Cloud Functions 在数据库中查找重复的用户名

标签 javascript firebase google-cloud-functions

按照我的建议,当新用户在使用 Firebase Cloud Functions 对用户进行身份验证之前注册时,我试图在数据库中查找重复的用户名,因为 .queryEqual(toValue) 本地不会出现”每次都工作。我现在无法理解的是如何在我的应用程序中使用它。这是我部署的云函数:

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database. 
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.uniqueUsername = functions.https.onRequest((req, res) => {
    const username = req.query.username
    admin.database().ref('users').orderByChild('username').equalTo(username).once('value').then(snap => {
        // if the child exists, then the username is taken
        if (snap.exists()) {
            res.send('username not available');
        } else {
            res.send('username available');
        }
    }); 
});

equalTo(username) 是从 UITextField 中选取的值,然后与数据库中的值进行比较。我在这里得到的错误是:

Error: Query.equalTo failed: First argument contains undefined in property 'users'
    at Error (native)
    at Ae (/user_code/node_modules/firebase-admin/lib/database/database.js:105:67)
    at ze (/user_code/node_modules/firebase-admin/lib/database/database.js:104:400)
    at W.h.Jf (/user_code/node_modules/firebase-admin/lib/database/database.js:142:60)
    at exports.uniqueUsername.functions.https.onRequest (/user_code/index.js:10:60)
    at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:47)
    at /var/tmp/worker/worker.js:649:7
    at /var/tmp/worker/worker.js:633:9
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickDomainCallback (internal/process/next_tick.js:122:9)

当我在浏览器中使用该 URL 时出现的错误是:

Error: could not handle the request

我做错了什么?接下来我应该做什么?

最佳答案

从该错误消息中,您将 undefined 值传递到 equalTo 函数中。

在执行查询(以及任何查询)之前,您想要使用 "fail-fast"方法。在本例中,如果 req.query.usernamefalsy ,返回错误。

exports.uniqueUsername = functions.https.onRequest((req, res) => {
  const username = req.query.username;
  if (!username) {
    res.status(400).json({error: 'Missing username GET parameter'});
    return;
  }
  // rest of your code.
}

更好的方法

对于任何需要唯一性的键,您都需要使用索引。在您的数据库中,它看起来类似于:

"/usernames": {
  "bob": "userId1",
  "frank": "userId2",
  "c00lguy": "userId3"
}

为了检查用户名是否免费,我建议首先让用户登录并进行身份验证。这可以确保我们有一个与用户名关联的用户 ID。他们登录后,检查他们是否尚未设置用户名,如果没有,则使用某种形式的对话框/输入提示他们设置用户名。

要检查用户名的可用性并在“单个”操作中声明它,您可以调用以下代码:(在内部它不是单个操作)

var desiredUsername = '...'; // from the form.
var userId = '...'; // the current logged in user's ID (normally from user.uid)
var ref = firebase.database().ref('/usernames').child(desiredUsername);
ref.transaction(function (currentData) {
  if (currentData !== null && currentData !== userId) {
    return; // returns undefined. Which aborts the operation because there is data here. (someone owns that username other than the current user).
  }
  // if here, username is available or owned by this user.
  return userId; // returning a value will write it to the database at the given location.
})
.then(function(transactionResult) {
  if (transactionResult.committed) {
    // username is now owned by current user
    // do something
  } else {
    // username already taken.
    // do something
  }
})
.catch(function (error) {
  // if here, an error has occured
  // (probably a permissions error, check database rules)
  // do something
});

此代码片段使用 Transaction操作允许您从数据库读取值,然后立即对其进行操作。在您的原始代码中,在您调用 uniqueUsername 函数并声明该用户名之间,其他人可以这样做。使用交易可以在用户知道用户名免费时立即声明其用户名,从而最大限度地减少执行此操作的机会窗口。

此方法比搜索数据库更快,并且允许您使用简单的查询按用户名查找用户。

以下代码是此类查询的示例,对于无人认领的用户名将返回 null

function findUserIdByUsername(username) {
  if (!username) {
    return Promise.reject('username is falsy');
  }
  firebase.database().ref('/usernames').child(username).once('value')
  .then(snapshot => {
    if (!snapshot.exists()) {
      return null; // no user with that username
    }
    return snapshot.val(); // the owner's user ID
  });
}

结合您的原始代码,它看起来像这样:

exports.uniqueUsername = functions.https.onRequest((req, res) => {
  const username = req.query.username;
  if (!username) {
    res.status(400).json({error: 'Missing username GET parameter'});
    return;
  }
  var ownerID = findUserIdByUsername(username);
  res.json({taken: (ownerID !== null)}); // Returns {"taken": "true"} or {"taken": "false"}
}

关于javascript - 使用 Firebase Cloud Functions 在数据库中查找重复的用户名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44987473/

相关文章:

Javascript变量范围和引用

android - "removeEventListener"(android) 是否关闭 Firebase 实时数据库连接?

Firebase 模拟器返回空数据,但部署后工作正常

google-cloud-platform - 如何通过 cli/rest api/cloud 函数运行 Google Cloud Build 触发器?

node.js - Firebase 功能部署失败

javascript - 如何通过用户输入用javascript刷新页面N次?

javascript - 如何让下面的函数返回 true 或 false?

javascript - SailsJS 与 EJS 返回 View 不渲染

ios - 使用 Swift 将多个子项添加到 Firebase 数据库

angular - 使用 AngularFire2 的 Firebase 数据库事务