1

Я застрял в этой проблеме уже много часов, поэтому любая помощь приветствуется. Попытка сделать приложение для Android с Firebase для аутентификации пользователей (простой адрес электронной почты и пароль) вместе с уникальными именами пользователей. У меня есть мои Регистраций экран поля выложена на одном экране, например:Firebase проверяет, существует ли значение без чтения моментального снимка или попытки записи (для уникальных имен пользователей)?

"Enter Username" 
"Enter Email Address" 
"Enter Password" 

Я очень смущен о том, как, как запрос к базе данных, чтобы проверить, если имя пользователя существует или нет без чтения снимка базы данных и без, пытающихся записать имя пользователя в базу данных (потому что это происходит, когда пользователь находится в состоянии auth == null, поэтому пока на странице регистрации до того, как пользователь создал свою учетную запись, я хочу сообщить пользователю, его имя пользователя принято или нет).

Я имею в виду, это чувствует, как это должно быть очень просто, простой запрос к Firebase со строкой и просто получить Firebase вернуться Правда или Ложные, но после нескольких часов прибегая к помощи я не смог найти ничего.

Причина, по которой я не хочу использовать снимок, заключается в том, что я не хочу публиковать все имена моих пользователей и их UID, установив «read» в true (я следовал этому руководству, поэтому мой правила безопасности настраиваются именно так, вместе с моей структурой базы данных Firebase android : make username unique).

Вот мои правила, и они работают в настоящее время (мне не нравится тот факт, что для чтения установлено значение Да, поэтому я задаю вопрос, хотя):

{ 
    "rules": { 
    "usernames": { 
     ".read": true, 
     "$username": { 
     ".write": "auth !== null && !data.exists()" 
     } 
    }, 
    "users": { 
     "$uid": { 
      ".write": "auth !== null && auth.uid === $uid && !data.exists()", 
      ".read": "auth !== null && auth.provider === 'password' && auth.uid === $uid", 
      "username": { 
       ".validate": "(!root.child('users').child(newData.val()).exists() || root.child('usernames').child(newData.val()).val() == $uid)" 
    } 
    } 
    } 
} 
} 

И это мои данные:

{ 
    "usernames" : { 
    "abcd" : "some-user-uid" 
    }, 
    "users" : { 
    "\"some-user-uid\"" : { 
     "username" : "abcd" 
    } 
    } 
} 

Спасибо!

ответ

1

К сожалению, нет возможности проверить, существуют ли данные, фактически не загружая их через SDK. Здесь будут построены структуры данных (рекомендуемое чтение: NoSQL Data Structures, и вы не должны бояться denormalize бит данных при оптимизации и масштабе.

Вообще говоря, вы должны хорошо структурировать свои данные, чтобы полезные если вы извлекаете то, что не может дождаться, когда байты будут извлечены (например, игры, странные одноразовые административные операции на очень больших наборах данных и т. д.), то вот несколько разумных подходов к моделированию это:

Получение списка ключей через REST API

Использование атрибута shallow=true в вызове API REST предотвратит загрузку большого набора данных и возвращает только ключи на этом пути. Обратите внимание: если вы храните миллион записей, их все равно нужно загружать в память на сервере (медленно), и вам все равно придется извлекать миллион строк (дорого).

Таким образом, один из способов проверить наличие данных на пути, без фактической загрузки данных, состоял бы в вызове пути, таком как https://<YOUR-FIREBASE-APP>.firebaseio.com/foo.json?shallow=true, и проверке того, возвращены ли какие-либо ключи.

Создание денормализованным индекса вы можете запросить вместо

Если вам действительно нужно выжать дополнительную производительность и скорость из вашей базы данных Firebase (подсказка: вам не нужно делать это, если вы не бежите миллионы запросов в минуту и, вероятно, только для игровой логики и подобных), вы можете двойной писать свои записи (т.е. денормализовать) следующим образом:

/foo/data/$id/... data goes here... 
/foo/index/$id/true (just a boolean value) 

для двойной записи, вы должны использовать команду обновления и записи аналогичны следующий (образец SDK для Android):

public void addRecord(Map<String, Object> data) { 
    DatabaseReference db = FirebaseDatabase.getInstance().getReference(); 

    // create a new record id (a key) 
    String key = db.child("foo").push().getKey(); 

    // construct the update map 
    Map<String, Object> dualUpdates = new HashMap<>(); 
    dualUpdates.put("/data/" + key, /* data here */); 
    dualUpdates.put("/index/" + key, true); 

    // save the new record and the index at the same time 
    db.child("foo").updateChildren(dualUpdates); 
} 

Теперь, чтобы определить, если запись существует, фактически не загружая данные, я могу просто запросить против /foo/index/$id и попробовать DataSnapshot.exists(), за счет загрузки одного логического значения.

+0

Спасибо за ответ! Какое решение вы предлагаете для максимальной безопасности данных? Я в порядке с моей текущей настройкой (потому что она работает), но read = true немного нервирует, потому что тогда любой может видеть все имена пользователей и их UID, правильно? – Aretyper

+0

Лучшей защитой было бы установить read: true для конкретных записей, но не разрешить чтение родительского пути. Это помешало бы любому просматривать uids; им нужно будет узнать идентификатор пользователя, чтобы просмотреть их. Я не знаю, что вы используете, поэтому я не могу предложить какие-либо конкретные советы. Но вы можете прочитать о проблеме [XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/66378#66378), так как вы можете просить неправильного вопросов. – Kato