Firebase实时数据库如何通过规则避免Resource集合重复数据
Firebase实时数据库规则优化:避免重复文档
问题背景
我在Firebase实时数据库中为Resource集合配置了如下规则:
{ "rules": { .... "Resource": { ".read": true, ".indexOn": ["FieldOne","FieldTwo"] }, .... } }
当前功能符合预期,但存在一个问题:重复执行CLI添加文档的命令时,会生成完全相同的文档。例如执行这条命令:
firebase database:push /..path../Resource --data '{"FieldOne":"field-1-value","FieldTwo":"field-2-value"}'
重复执行后,数据库中会出现多个FieldOne和FieldTwo值完全一致的文档。
需求
仅通过数据库规则实现以下限制:
- 允许添加单个字段值不同的文档(比如
FieldOne为field-1-value、FieldTwo为field-5-value的文档) - 禁止添加两个字段值均与现有文档完全相同的重复文档
解决方案
要实现这个需求,需借助Firebase规则的查询能力,结合反向索引来校验字段组合的唯一性。
1. 设计反向索引结构
在数据库中新增一个ResourceIndex节点,用来记录已存在的FieldOne+FieldTwo组合,结构示例:
{ "ResourceIndex": { "field-1-value_field-2-value": true, "field-1-value_field-5-value": true } }
这个索引的键是FieldOne和FieldTwo的值拼接而成(可自定义分隔符,避免字段值本身包含分隔符的冲突),值固定为true即可。
2. 更新数据库规则
修改规则,在写入Resource文档时校验索引中是否存在相同组合,同时确保索引与主数据同步:
{ "rules": { "Resource": { ".read": true, ".indexOn": ["FieldOne", "FieldTwo"], "$resourceId": { // 仅允许创建新文档,且对应的字段组合未在索引中存在 ".write": "!data.exists() && !root.child('ResourceIndex').child(newData.child('FieldOne').val() + '_' + newData.child('FieldTwo').val()).exists()", // 校验文档必须包含FieldOne和FieldTwo ".validate": "newData.hasChildren(['FieldOne', 'FieldTwo'])" } }, "ResourceIndex": { // 仅当对应的Resource文档存在时,才能写入索引 ".write": "root.child('Resource').child(newData.parent().key()).exists()", "$indexKey": { // 索引值必须为true,保证结构规范 ".validate": "newData.val() === true" } } } }
3. 调整CLI写入命令
由于需要同步写入主数据和索引,需将原push命令改为update命令,保证原子性:
firebase database:update / --data '{ "..path../Resource": {"FieldOne":"field-1-value","FieldTwo":"field-2-value"}, "..path../ResourceIndex/field-1-value_field-2-value": true }'
规则说明
Resource/$resourceId/.write:通过!data.exists()确保是创建新文档,!root.child('ResourceIndex').child(...)检查字段组合未被占用,双重限制避免重复。ResourceIndex的规则:保证索引只能与Resource的文档关联写入,防止出现无对应文档的脏索引数据。
内容的提问来源于stack exchange,提问作者Michel
相关产品推荐
相关产品推荐

