Vic
Vic

Reputation: 424

Firebase removing from lookup by key

This is a very simple question. I have a lookup location where I store whether username has been taken. The format is username:userid its all good when I don't want to keep my db clean but I do. To stop it from ever growing I added this - it works but it feels like a very hacky approach.

this.db.database.ref('usernames').on('child_added',snapshot => {
  if (snapshot.val() === userId && snapshot.key !== username) {
    this.db.object(`usernames/${snapshot.key}`).remove();
  }
});

It works fine does what I want it to do but it feels very very "dirty" if you know what I mean.

There must be a better way to remove all records which key !== new_key and value === $uid.

Upvotes: 0

Views: 48

Answers (1)

ProfDFrancis
ProfDFrancis

Reputation: 9411

I think I understand what you are doing. You have a branch of your database called "usernames", under which you have a list of key-value pairs. The keys are usernames, short memorable names made up by users, for example "bob1" or "darthVader111". For each, the value is the Firebase UserId of the user, which is the long unmemorable code such as "4jkh53kjh543g3ij4534k5j43h5k".

database
    usernames
        bob1 (key): 4jkh53kjh543g3ij4534k5j43h5k (value)
        darthvader (key): 098769456435k6645kjhlsdfkjh (value)
        ...

Your code is waiting for any additions to the usernames branch of your database, and looking at the key-value pair that is added. If you are currently logged in as Firebase UserID "4jkh53kjh543g3ij4534k5j43h5k", and your username is "bob1", and the code sees a new child being added, whose username is "Roberto", with the same Firebase UserID "4jkh53kjh543g3ij4534k5j43h5k", then it knows know that the user (whose Firebase UserID is constant) must have changed his/her username.

It is therefore reasonable to delete the (old) username entry, {"bob1": "4jkh53kjh543g3ij4534k5j43h5k"}.

I think it is ingenious because it doesn't require searching. Wouldn't it be neater, though, not to have to wait for "child_added", but instead do it in the code that creates the new username entry? For example:

  let userObject={};
  userObject[newUserName]=userId;

  this.db.object(`usernames/${oldUserName}`).remove()
  .then(this.db.object("usernames").update(userObject))

Security concerns

It looks like you are letting the end-user write, effectively anywhere he/she likes, into the usernames tree. You could make it more secure with Validation rules at the firebase server.

In particular, you would probably want to prevent the end-user (who may be able to manipulate the javascript to remove the ".remove()" call) from taking over vast numbers of user Ids.

One solution for this is to have two username databases: one keyed as you have done, as username:userId, and the other userId:username. You can set validation rules that an update must

  • update both subtrees with identical data (obviously with key and value reversed),
  • the username mustn't exist in the "username:userId" subtree
  • the userId mustn't exist in the "userId:username" subtree

This way, if the user removes the ".remove()" call in the javascript, he/she will not be able to take over a new userId.

Upvotes: 1

Related Questions