Firebase Realtime DB如何配置规则避免写入已存在的ExponentPushToken
原有规则失效原因
- 路径匹配错误:你的规则定义在根节点下,
data.child('push_token')取的是根目录的push_token节点,而实际你的push_token在users节点下,路径不匹配导致校验逻辑完全取错了值。 - 对比逻辑错误:
data.child('push_token').val()返回的是整个push_token节点的对象(包含所有自动生成key和对应token的键值对),和你新写入的单个token字符串对比永远不相等,校验自然不生效。 - 未适配push操作特性:每次调用push()会生成随机新key,写入路径是
users/push_token/[新随机key],原有规则没有遍历所有已存token做判断,拦不住重复写入。
推荐解决方案(改存储结构,性能最优)
直接用ExponentPushToken作为节点key,利用Firebase节点key天然唯一的特性实现去重,规则实现最简单,性能最高。
调整后存储结构
{ "users" : { "push_tokens" : { "转义后的ExponentPushToken值" : true } } }
注:ExponentPushToken自带的[、]字符可以在前端写入前替换为下划线等合法字符,避免路径解析异常
对应规则配置
{ "rules": { ".read": "false", "users": { "push_tokens": { "$token": { // 仅当该token对应的节点不存在时允许写入 ".write": "!data.exists()" } } } } }
前端写入时不要用push()方法,直接调用set()写入到users/push_tokens/[转义后的token]路径,值设为true即可,已存在的token会被规则直接拦截写入
兼容现有存储结构的解决方案
如果不想调整现有存储结构,继续使用自动生成key的模式,可以用以下规则:
{ "rules": { ".read": "false", "users": { "push_token": { "$autoKey": { // 校验新写入的token在所有已存token中不存在 ".write": "data.parent().children().filter(child => child.val() === newData.val()).length === 0" } } } } }
注:该方案需要遍历所有已存token做判断,当push_token下数据量较大时写入性能会明显下降,仅推荐数据量较小的场景使用
内容的提问来源于stack exchange,提问作者Mark-The-Guitar-Guy
相关产品推荐
相关产品推荐

