1

I am trying to create a separate datastore for unique usernames and extra profile data such as avatar etc. I have the following schema:

mydatabase : {
   users: [{
     <actual user's id>: {
        username: "helloworld"
     },
     <actual user's id>: {
        username: "2test"
     }]
}

Is my approach correct on this? I didn't see a way in firebase to store usernames or extra user data in the Authentication records of firebase. Also I noticed most examples I find online generate a push key for each row of data, but here I am using the actual user's id instead of a push key. I want to eventually query this when a user tries to create a username to see if it's been taken already.

anthonypliu
  • 12,179
  • 28
  • 92
  • 154

1 Answers1

3

I would use the same approach you're using. I agree that it makes sense to use the userId as the key instead of a pushId since, as you point out, you'll want to query the data later on.

The only potential challenge of using this structure is if you want users to pick a username at the time the user is created, they will not have read access to the database so they won't be able to check if the username is unique. As long as you're ok with creating a user first and then having them choose a username once authenticated, this won't be a problem. If you'd prefer that they choose a username first, then you could use Cloud Functions for Firebase with an HTTP trigger, and pass the username as part of the request. The request would include a query of the given username and the response would return whether the username is available or not. It could look something like this:

const functions = require('firebase-functions');
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');
        }
    })   
}
Jen Person
  • 7,356
  • 22
  • 30
  • So i did a bit more research and found this: https://stackoverflow.com/questions/35255518/query-a-specific-child-node-in-all-instances-of-a-parent-node-in-firebase i have to create a seperate datastore called "usernames" and have each username associated to a userid,so i can query to find out if the username is available or not. I don't think i can do what you said in the example because each userid is unique, it works, but i get a warning like this: `FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "username" at /users to your security rules for better performance ` – anthonypliu Jul 05 '17 at 19:16
  • So add `indexOn` to your security rules to improve performance. It usually makes sense to denormalize the database, but in this context, there isn't much use for having a separate node of usernames. The query from my answer will return one or no results and will not impact the client performance since it is run server-side. – Jen Person Jul 05 '17 at 19:39
  • In other words, even if my user store got up to millions of users, my approach would still be overkill? I am not opposed to using your approach at all, i like the fact that the data is much cleaner and can be found in just once place. I am just worried if your approach is scalable? I am totally new to firebase btw :) – anthonypliu Jul 05 '17 at 19:58
  • Sure, I'd say both approaches have benefits and drawbacks. Denormalization is a good approach. In my example, you don't have to update multiple children when a user is added or deleted. In your example, you don't have to deal with the additional cost of indexing. – Jen Person Jul 05 '17 at 23:06