首页 > 解决方案 > 使用 Go 从 Firestore 获取单个文档的惯用方式是什么?

问题描述

我正在编写一个 Go 服务,它检索具有给定 ID 的单个 Firestore 文档。实施草案如下。该代码似乎工作。GetAccount返回 a map[string]interface{},它是nil或设置为文档数据的表示形式。

go doc firestore.DocumentRef.Get显示:

func (d *DocumentRef) Get(ctx context.Context) (_ *DocumentSnapshot, err error) Get 检索文档。如果文档不存在,Get 返回 NotFound 错误,可以用

   status.Code(err) == codes.NotFound

在这种情况下,Get 返回一个非 nil DocumentSnapshot,其 Exists 方法返回 false,其 ReadTime 是读取操作失败的时间。

如果 a已经表明它的存在,为什么DocumentSnapshot还包含一个Exists()方法?status.Code(err) == codes.NotFound

go doc firestore.DocumentSnapshot.DataTo还说:

如果文档不存在,DataTo 将返回 NotFound 错误。

我是否也应该status.Code(err) == codes.NotFound在代码路径中的 B 点进行检查?

type srv struct {
    fs *firestore.Client
}

// ...

m, err := srv.GetAccount(ctx, "81199475")
if err != nil {
    log.Fatal(err)
}
if m == nil {
    fmt.Println("NOT FOUND")
    os.Exit(0)
}
fmt.Printf("%#v\n", m)

func (s *srv) GetAccount(ctx context.Context, id string) (map[string]interface{}, error) {
    docSnap, err := s.fs.Doc("accounts/" + id).Get(ctx)
    if status.Code(err) == codes.NotFound {
        return nil, nil
    }
    if err != nil {
        return nil, err
    }

    var m map[string]interface{}
    if err := docSnap.DataTo(&m); err != nil {
        // Point B
        return nil, err
    }
    return m, nil
}

更新:有人指出,与其GetAccount返回nil指示未找到文档,不如将底层 Firestore 错误传播到调用堆栈上,或者提供自定义错误。

var ErrAccountNotFound = errors.New("account/account-not-found")

// ...

if status.Code(err) == codes.NotFound {
    return nil, ErrAccountNotFound
}

标签: gogoogle-cloud-firestorefirebase-admin

解决方案


您只需要检查从Get.

DocumentSnapshot.Exists()方法对于GetAll返回多个快照之类的方法很有用。当未找到单个文档时,这些方法不会返回错误。

使用以下代码简化代码DocumentSnapshot.Data()

func (s *srv) GetAccount(ctx context.Context, id string) (map[string]interface{}, error) {
    docSnap, err := s.fs.Doc("accounts/" + id).Get(ctx)
    if err != nil {
        // Translate firestorm not found to application specific not found.
        if status.Code(err) == codes.NotFound {
            err = ErrAccountNotFound
        }
        return nil, err
    }
    return docSnap.Data(), nil
}

推荐阅读