1

I want to create a user registration with custom usernames. I store the user's username on a user document in Firestore. How can I validate a username already exists in my Users Collection?

Maybe someone already have snippet for reactive form validation?

Dan Broadbent
  • 93
  • 1
  • 7
Volodymyr Humeniuk
  • 3,411
  • 9
  • 35
  • 70
  • 1
    try and get it `where username== usernameVariable` and if there is a result then that username is already a username in the db. you should use firebase.auth. – Ronnie Royston Mar 19 '18 at 20:59

3 Answers3

9

There is no efficient way to check all documents in a collection for a specific value. You would have to read each document in turn, and check them. That is prohibitive both from a performance and a cost standpoint.

What you can instead do is create an additional collection (typically called a reverse index, or reverse map) where you use the username as the name of the document, and (for example) the user's UID as the data of the document. You can then easily check if a username is already taken by checking for the existence of a document with that specific name, which is a direct access lookup and thus highly scaleable.

Since you tagged with google-cloud-datastore; if you are indeed looking for an answer for that database too, check Unique email in Google Datastore.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
2

Here is angular code:

 fs_collection: AngularFirestoreCollection<UserItems>;

 this.db.collection<UserItems>('Users’).ref.where('username', '==',
 this.model.username).get().then((ref) => {

             let results = ref.docs.map(doc => doc.data() as UserItems);
             if (results.length > 0) {
                console.log(userData); //do what you want with code
            }
             else {
                 this.error(“no user.”);
             }
         });
Mayuri R Talaviya
  • 613
  • 1
  • 9
  • 14
0

In my Angular/Ionic project, I use an async validator to check for existing usernames stored as fields on user documents in a users collection. In my constructor I have:

this.signupForm = formBuilder.group({
  username: ['', Validators.compose([Validators.required, 
                                     Validators.minLength(2),
                                     Validators.maxLength(24), 
                                     this.asyncValidator.bind(this)],
  password: ['', Validators.compose([Validators.minLength(6), 
                                     Validators.required])]
})

My asyncValidator method:

asyncValidator(control) {
  let username = control.value
  return new Promise(resolve => {
    this.checkUsername(username).then(snapshot => {
      if(snapshot.docs.length > 0){
        resolve({
          "username taken": true
        });
      } else {
        resolve(null);
      }
    })
  })
}

My query to Firestore:

checkUsername(username) {
  return firebase.firestore().collection('users').where("username", "==", username).get()
}
Dan Broadbent
  • 93
  • 1
  • 7