Go操作Firestore判断文档是否存在时触发NotFound错误如何处理
问题结论
你的调整方向完全正确,仅需要补充错误类型判断逻辑即可,你当前写的二次doc.Exists()判断属于冗余逻辑,且存在逻辑隐患。
原理说明
根据Firestore官方Get()方法的定义:
Get retrieves the document. If the document does not exist, Get return a NotFound error, which can be checked with
status.Code(err) == codes.NotFound;In that case, Get returns a non-nil DocumentSnapshot whose Exists method return false.
对应行为规则如下:
- 文档存在时,
Get()返回nil错误,返回的DocumentSnapshot的Exists()固定为true - 文档不存在时,
Get()同时返回NotFound错误和非空的DocumentSnapshot,此时快照的Exists()返回false - 其他错误场景(网络异常、权限不足等)会返回对应错误,无有效快照返回
你最初的代码没有区分错误类型,直接把所有错误返回,才会走不到后续的存在性判断分支。
现有调整代码的问题
- 缺失必要依赖导入:需要额外导入两个gRPC相关包才能使用
status和codes判断错误类型:
import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" )
- 二次判断逻辑冗余且错误:
- 如果
Get()没有返回错误,说明文档一定存在,doc.Exists()必然返回true,不需要额外判断 - 你在NotFound分支处理完写入逻辑后没有跳出,会继续走到后续的
doc.Exists()判断,但此时的doc是之前Get()返回的不存在的快照,会导致判断逻辑不符合预期
优化后正确实现
package main import ( "context" "errors" "log" "cloud.google.com/go/firestore" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func main() { ctx := context.Background() client, err := firestore.NewClient(ctx, "PROJECTID") if err != nil { log.Fatalln(err) } defer client.Close() docRef := client.Collection("claimed").Doc("123abc") doc, err := docRef.Get(ctx) if err != nil { // 非文档不存在的错误直接抛出 if status.Code(err) != codes.NotFound { log.Fatalln(err) } // 文档不存在,执行写入逻辑 _, err = docRef.Set(ctx, /* 此处替换为自定义对象 */) if err != nil { log.Fatalln(err) } return } // 走到此处说明文档已存在,直接处理存在逻辑即可 log.Fatalln(errors.New("document ID already exists")) }
补充提示
如果你的业务场景存在并发写入的可能,建议将整个判断+写入逻辑放到Firestore事务中执行,避免出现两个请求同时判定文档不存在、重复写入的问题。
内容的提问来源于stack exchange,提问作者Ari
相关产品推荐
相关产品推荐

