Como você evita propriedades de usuário duplicadas no Firebase?

Estou usando o FirebaseSimpleLogin para criar usuários e lidar com autenticação.

Quando tento criar um novo usuário com login simples por meio do método $createUser() , o Firebase não cria o usuário se o endereço de e-mail já tiver sido usado. No entanto, também estou usando $set() para salvar meus usuários criados no meu Firebase depois de criá-los e estou usando o user.uid como chave. Ao tentar gravar no database, o firebase salvará o registro, mesmo que o nome de usuário não seja único, já que apenas email e senha são necessários para um login simples. Então, como posso validar um nome de usuário para ser único quando ele não está sendo usado como a chave para o object de usuário?

Estou criando novos usuários assim:

 $scope.createUser = function() { $scope.auth.$createUser('trinker@gmail.com', 'password').then(function(user, err) { if (!err) { ref.child('users/' + user.uid).set({ email: user.email, username: user.username }); console.log("success!"); }else{ console.log(err.message); } }); } 

E meu object de usuário é assim:

 { "users" : { "simplelogin:28" : { "email" : "trinker@gmail.com", "username" : "jtrinker" }, "simplelogin:30" : { "email" : "test@gmail.com", "username" : "jtrinker" } } } } 

Eu preciso usar o uid como a chave para cada usuário, mas ainda preciso que o nome de usuário seja único.

Como posso evitar que o Firebase salve registros se as propriedades em um object não forem exclusivas das propriedades dentro de um object diferente?

Primeiro de tudo, se os usuários já tiverem um username , ele é único, e isso não vai desaparecer, eu recomendo que você desista de usar o login simples. Isso não criará nada além de questões que tentam alternar entre os dois, como você já descobriu aqui. Investigue a criação de seus próprios tokens com uma ferramenta como firebase-passport-login e armazene os registros por username de username .

Mas como essa não foi a sua pergunta, vamos resolver isso enquanto estivermos aqui, já que você pode querer ir em frente e entrar no espinhoso briar de identidades duais pelas quais passei muitas vezes.

Para tornar o nome de usuário exclusivo, armazene um índice de nomes de usuários.

 /users/$userid/username/$username /usernames/$username/$userid 

Para garantir que sejam exclusivos, adicione uma regra de segurança da seguinte maneira no ID do usuário em nomes de usuário / caminho, o que garante que apenas um usuário possa ser atribuído por nome de usuário e que o valor seja o ID do usuário:

 ".write": "newData.val() === auth.uid && !data.exists()" 

Agora imponha que eles correspondam adicionando o seguinte ao nome de usuário nos usuários / registro:

 "users": { "$userid": { "username": { ".validate": "root.child('usernames/'+newData.val()).val() === $userid" } } } 

Isso garantirá que os IDs sejam exclusivos. Tenha cuidado com os privilégios de leitura. Você pode querer evitá-los totalmente, já que não quer que alguém procure e-mails ou nomes de usuários. Algo como eu demonstrei em apoio para salvar estes seria o ideal.

A ideia aqui é que você tente atribuir o nome de usuário e o email, se eles falharem, eles já existirão e pertencerão a outro usuário. Caso contrário, você os insere no registro do usuário e agora tem usuários indexados por uid e email.

Para cumprir com o protocolo SO, aqui está o código da essência, que é melhor ler através do link:

 var fb = new Firebase(URL); function escapeEmail(email) { return email.replace('.', ','); } function claimEmail(userId, email, next) { fb.child('email_lookup').child(escapeEmail(email)).set(userId, function(err) { if( err ) { throw new Error('email already taken'); } next(); }); } function claimUsername(userId, username, next) { fb.child('username_lookup').child(username).set(userId, function(err) { if( err ) { throw new Error('username already taken'); } next(); }); } function createUser(userId, data) { claimEmail(userId, data.email, claimUsername.bind(null, userId, data.username, function() { fb.child('users').child(userId).set(data); ); } 

E as regras:

 { "rules": { "users": { "$user": { "username": { ".validate": "root.child('username_lookup/'+newData.val()).val() === auth.uid" }, "email": { ".validate": "root.child('email_lookup').child(newData.val().replace('.', ',')).val() === auth.uid" } } }, "email_lookup": { "$email": { // not readable, cannot get a list of emails! // can only write if this email is not already in the db ".write": "!data.exists()", // can only write my own uid into this index ".validate": "newData.val() === auth.uid" } }, "username_lookup": { "$username": { // not readable, cannot get a list of usernames! // can only write if this username is not already in the db ".write": "!data.exists()", // can only write my own uid into this index ".validate": "newData.val() === auth.uid" } }, } } 

Não seria mais fácil apenas usar as regras de segurança para verificar sua existência? Eu tenho o meu criado da seguinte forma:

 "usernames": { "$usernameid": { ".read": "auth != null", ".write": "auth != null && (!data.exists() || !newData.exists())" } } 

Isso permite a gravação se o nome de usuário não existir. Acredito que recebi isso diretamente dos documentos do Firebase.