Правила безопасности Firebase не могут применять уникальное значение в указанном свойстве c для одного узла. Но (как это часто бывает с базами данных SQL), вы можете использовать конкретную модель данных c для реализации варианта использования.
Обычное решение для этого - использовать UID избирателя. в качестве ключа.
votes
uid1: "candidate A"
uid2: "candidate B"
uid3: "candidate A"
Поскольку ключи должны быть уникальными в объекте JSON, эта структура по определению гарантирует, что каждый UID может голосовать только один раз.
Это отдельно от сохранения общего количества голосов за кандидата. Для этого вы можете использовать либо правила безопасности, либо облачные функции.
Выполнение этого в целях безопасности является привлекательным, поскольку это означает, что вам не понадобится код на стороне сервера. Но правила могут стать довольно сложными. Пример этого см. В моем ответе на этот вопрос: Безопасен ли способ быстрого запуска базы данных Firebase?
Более простой и в наши дни более распространенный подход заключается в том, чтобы сделать это с облачной функцией. Из недавнего проекта, над которым я работал, у меня есть эта облачная функция:
exports.countVote = functions.database.ref('/votes/{uid}').onCreate((snapshot, context) => {
let value = snapshot.val();
let countRef = snapshot.ref.parent.parent.parent.child(`totals/${value}`);
return countRef.transaction(function(current) {
return (current || 0) + 1;
})
});
Так что это подсчитывает голоса для каждого уникального значения. Затем он гарантирует, что пользователи не смогут изменить свой существующий голос с:
{
"rules": {
"votes": {
"$uid": {
".write": "auth.uid === $uid && !data.exists()"
}
}
}
}
Таким образом, пользователь может голосовать, только если он использует свой собственный UID (переменная auth.uid
предварительно заполнена и не может быть подделана) и если они еще не проголосовали.