我是否需要额外往返 firestore 来读取创建和更新的时间戳字段?

2024年 2月 11日 66.6k 0

我是否需要额外往返 firestore 来读取创建和更新的时间戳字段?

在使用Firestore时,你可能会疑惑是否需要额外的往返操作来读取创建和更新的时间戳字段。答案是不需要。Firestore会自动为每个文档提供创建和更新时间戳,你可以通过引用这些字段来获取相应的时间信息。这样,你就不需要额外的操作来读取时间戳字段,可以更便捷地获取到文档的创建和更新时间。这样的设计使得在开发过程中更加高效和简化,避免了不必要的代码和请求。

问题内容

  • 好的,我在 go 中有一个 rest api ,它使用 firestore 存储 ticket 资源。为此,我使用:firestore go client

  • 我希望能够通过 date 创建/更新日期 对我的文档进行排序,因此按照文档,我将这 2 个字段作为时间戳存储在文档中。

  • 我在这两个字段上使用标签 servertimestamp 。通过这样做,该值应该是 firestore 服务器处理请求的时间。

  • 更新操作的 http 响应应包含以下正文:

  • {
    "ticket": {
    "id": "af41766e-76ea-43b5-86c1-8ba382edd4dc",
    "title": "ticket updated title",
    "price": 9,
    "date_created": "2023-01-06 09:07:24",
    "date_updated": "2023-01-06 10:08:24"
    }
    }

    登录后复制

    这意味着在我更新票证文档后,除了更新的 title 或 price 之外,我还需要更新 date_updated 字段的值。

    目前可行,但我很好奇我编码的方式是否就是这样做的方式。正如您在代码示例中看到的,我使用事务来更新票证。除了再次读取更新的票证之外,我没有找到检索 dateupdated 字段的更新值的方法。

    域实体定义如下:

    package tixer

    import (
    "context"
    "time"

    "github.com/google/uuid"
    )

    type (

    // ticketid represents a unique identifier for a ticket.
    // it's a domain type.
    ticketid uuid.uuid

    // ticket represents an individual ticket in the system.
    // it's a domain type.
    ticket struct {
    id ticketid
    title string
    price float64
    datecreated time.time
    dateupdated time.time
    }

    )

    登录后复制

    我将在此处附加从创建和更新角度与 firestore 的通信:

    // Storer persists tickets in Firestore.
    type Storer struct {
    client *firestore.Client
    }

    func NewStorer(client *firestore.Client) *Storer {
    return &Storer{client}
    }

    func (s *Storer) CreateTicket(ctx context.Context, ticket *tixer.Ticket) error {
    writeRes, err := s.client.Collection("tickets").Doc(ticket.ID.String()).Set(ctx, createTicket{
    Title: ticket.Title,
    Price: ticket.Price,
    })

    // In this case writeRes.UpdateTime is the time the document was created.
    ticket.DateCreated = writeRes.UpdateTime

    return err
    }

    func (s *Storer) UpdateTicket(ctx context.Context, ticket *tixer.Ticket) error {
    docRef := s.client.Collection("tickets").Doc(ticket.ID.String())
    err := s.client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
    doc, err := tx.Get(docRef)
    if err != nil {
    switch {
    case status.Code(err) == codes.NotFound:
    return tixer.ErrTicketNotFound
    default:
    return err
    }
    }
    var t persistedTicket
    if err := doc.DataTo(&t); err != nil {
    return err
    }
    t.ID = doc.Ref.ID

    if ticket.Title != "" {
    t.Title = ticket.Title
    }
    if ticket.Price != 0 {
    t.Price = ticket.Price
    }

    return tx.Set(docRef, updateTicket{
    Title: t.Title,
    Price: t.Price,
    DateCreated: t.DateCreated,
    })
    })
    if err != nil {
    return err
    }

    updatedTicket, err := s.readTicket(ctx, ticket.ID)
    if err != nil {
    return err
    }
    *ticket = updatedTicket

    return nil
    }

    func (s *Storer) readTicket(ctx context.Context, id tixer.TicketID) (tixer.Ticket, error) {
    doc, err := s.client.Collection("tickets").Doc(id.String()).Get(ctx)
    if err != nil {
    switch {
    case status.Code(err) == codes.NotFound:
    return tixer.Ticket{}, tixer.ErrTicketNotFound
    default:
    return tixer.Ticket{}, err
    }
    }

    var t persistedTicket
    if err := doc.DataTo(&t); err != nil {
    return tixer.Ticket{}, err
    }
    t.ID = doc.Ref.ID

    return toDomainTicket(t), nil
    }

    type (
    // persistedTicket represents a stored ticket in Firestore.
    persistedTicket struct {
    ID string `firestore:"id"`
    Title string `firestore:"title"`
    Price float64 `firestore:"price"`
    DateCreated time.Time `firestore:"dateCreated"`
    DateUpdated time.Time `firestore:"dateUpdate"`
    }

    // createTicket contains the data needed to create a Ticket in Firestore.
    createTicket struct {
    Title string `firestore:"title"`
    Price float64 `firestore:"price"`
    DateCreated time.Time `firestore:"dateCreated,serverTimestamp"`
    DateUpdated time.Time `firestore:"dateUpdate,serverTimestamp"`
    }
    // updateTicket contains the data needed to update a Ticket in Firestore.
    updateTicket struct {
    Title string `firestore:"title"`
    Price float64 `firestore:"price"`
    DateCreated time.Time `firestore:"dateCreated"`
    DateUpdated time.Time `firestore:"dateUpdate,serverTimestamp"`
    }
    )

    func toDomainTicket(t persistedTicket) tixer.Ticket {
    return tixer.Ticket{
    ID: tixer.TicketID(uuid.MustParse(t.ID)),
    Title: t.Title,
    Price: t.Price,
    DateCreated: t.DateCreated,
    DateUpdated: t.DateUpdated,
    }
    }

    登录后复制

    解决方法

    如果我理解正确的话,DateUpdated字段是一个服务器端时间戳,这意味着它的值是由服务器在将该值写入存储层时确定的(即所谓的字段转换)。由于 Firestore SDK 中的写入操作不会返回该操作的结果数据,因此将该值返回到应用程序中的唯一方法实际上是在写入后执行额外的读取操作来获取它。

    SDK 不会自动执行此读取,因为这是一个收费操作,很多情况下是不需要的。因此,通过让您的代码来执行该读取,您可以决定是否产生此成本。

    以上就是我是否需要额外往返 firestore 来读取创建和更新的时间戳字段?的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论