Firestore规则实现手机号唯一性校验(不影响现有系统)
解决Firestore规则实现手机号全局唯一的问题
我明白你的痛点:现有系统依赖当前的数据库结构不能改动,只能通过Firestore规则来阻止重复手机号,同时还要保证用户只能操作自己的数据。之前的尝试逻辑不对,因为resource.data.phone只是当前文档的字段,没法检查整个集合的情况,下面给你一个可行的规则方案:
核心思路
要实现两个核心限制:
- 用户仅能读写自己
Users/{userId}下的文档(userId必须匹配request.auth.uid) - 当写入(创建或更新)包含手机号的请求时,确保整个Users集合中没有其他文档使用该手机号(用户更新自己手机号时,允许保留原手机号)
最终Firestore规则
service cloud.firestore { match /databases/{database}/documents { // 处理Users集合的读写权限 match /Users/{userId} { // 用户只能读取自己的文档 allow read: if request.auth.uid == userId; // 写入权限:仅允许操作自己的文档,且手机号唯一(或未修改手机号) allow write: if request.auth.uid == userId && ( // 场景1:修改的内容不涉及手机号(比如更新姓名、地址) !request.resource.data.keys().has("phone") || // 场景2:未修改手机号(更新其他内容,或创建时手机号与自身一致——创建时resource不存在,此条件自动跳过) request.resource.data.phone == resource.data.phone || // 场景3:创建新文档/更新新手机号,检查全局无重复 !exists(/databases/$(database)/documents/Users, where: "phone", "==", request.resource.data.phone) ); } // 保留原有user-compare集合的规则 match /user-compare/{anything=**} { allow read: if true; } } }
规则细节解释
- 基础权限控制:
request.auth.uid == userId确保用户只能操作自己的文档,符合你的读写权限要求。 - 多场景覆盖:
- 当用户修改姓名、地址等不涉及手机号的字段时,直接允许写入,不用检查唯一性。
- 当用户更新内容但未改动手机号时,也直接允许,避免不必要的查询。
- 当用户创建新账号(写入全新文档)或更新手机号为新值时,通过
exists()函数查询整个Users集合,确认没有其他文档使用该手机号,才允许写入。
关键注意事项
- 索引优化:为了让
exists()查询高效执行,建议给Users集合的phone字段创建一个单字段索引。你可以在Firebase控制台的Firestore索引页面添加,避免规则执行超时。 - 移除重复规则:你原来的规则中有
match /Users/{anything=**},这会和match /Users/{userId}产生冲突,建议删除前者,因为更具体的匹配规则会优先生效。 - 兼容性:这个规则完全基于现有数据库结构实现,不会影响正在运行的系统——现有系统的手机号不会被修改,只有你的新应用在写入时会触发唯一性检查,避免产生重复手机号导致系统崩溃。
内容的提问来源于stack exchange,提问作者Ibrahim Usman
相关产品推荐
相关产品推荐

