2

I have a simple app, where a user can register with email and password and later on they can change their username. This is my onSignUp method:

onSignUp() {
    const { email, password, userName } = this.state;

    this.validate({
      userName: { minlength: 3, maxlength: 20, required: true },
      email: { email: true, required: true },
      password: { minlength: 5, required: true },
    });
    firebase
      .auth()
      .createUserWithEmailAndPassword(email, password)
      .then((result) => {
        firebase
          .firestore()
          .collection("users")
          .doc(firebase.auth().currentUser.uid)
          .set({
            email,
            username,
          });
      })
      .catch((error) => {
        this.setState({ error: error.message });
      });
  }

Later on, I want to give the user opportunity to change their userName. How do I enforce unique userNames? One way I can think of, is first perform query, on firebase to check if such username exist? Is this the right way to do so? Another way (for which I read, but I dont understand fully) is by enforcing firebase rules? If so, how do I create new rule and how do I set unique usernames? Or should I do it both ways?

newbie coder
  • 644
  • 5
  • 18
  • This has been covered quite a few times on Stack Overflow already: the only way to ensure uniqueness of a field is to use that field as the ID for the documents in a collection. So if you want unique user names, you'll need to have a collection (typically an additional collection) where you store documents with the user names as the IDs. Instead of reposting the same solution again, I recommend you study some of [these](https://stackoverflow.com/search?q=%5Bgoogle-cloud-firestore%5D+unique+username), and post back if you tried the solutions from there in your own code. – Frank van Puffelen Jul 05 '21 at 15:19

1 Answers1

1

You can try this function:

const usersColRef = firebase.firestore().collection("users")

async function isUsernameUnique (username) {
  try {
    const nameDoc = await usersColRef.where("username", "==", username).get()
    return !nameDoc.exists
  } catch (e) {
    console.log(e)
    return false
  }
}

// Use it as follows (make sure this is in an async function)
if (await isUsernameUnique("myCoolName")) {
  //proceed
} else {
  alert("Name is already taken. Show some more creativity ;)")
}

I'd recommend storing a separate field called "nameLower" and then pass the entered username in lowercase in the where() query as it's case sensitive, i.e. .where("nameLower", "==", username.toLowerCase())

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
  • 1
    While this does indeed check whether a document with a specific user name exists, it does not guarantee uniqueness. Malicious users may not be running this code, and thus can create whatever user names they want. The only way to ensure uniqueness is to use the user name as the ID for documents in a collection, and then reject overwrites from unauthorized users in security rules. – Frank van Puffelen Jul 05 '21 at 15:21