Heim  >  Artikel  >  Backend-Entwicklung  >  Benötige ich einen zusätzlichen Roundtrip zum Firestore, um die erstellten und aktualisierten Zeitstempelfelder zu lesen?

Benötige ich einen zusätzlichen Roundtrip zum Firestore, um die erstellten und aktualisierten Zeitstempelfelder zu lesen?

PHPz
PHPznach vorne
2024-02-11 18:36:091194Durchsuche

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

Bei der Verwendung von Firestore fragen Sie sich möglicherweise, ob zusätzliche Roundtrips erforderlich sind, um die erstellten und aktualisierten Zeitstempelfelder zu lesen. Die Antwort ist nein. Firestore stellt automatisch Erstellungs- und Aktualisierungszeitstempel für jedes Dokument bereit, und Sie können die entsprechenden Zeitinformationen erhalten, indem Sie auf diese Felder verweisen. Auf diese Weise sind keine zusätzlichen Vorgänge zum Lesen des Zeitstempelfelds erforderlich und Sie können die Erstellungs- und Aktualisierungszeit des Dokuments einfacher ermitteln. Dieses Design macht den Entwicklungsprozess effizienter und vereinfacht und vermeidet unnötigen Code und Anfragen.

Frageninhalt

  1. Okay, hier bin ich go 中有一个 rest api ,它使用 firestore 存储 ticket Ressourcen. Hierfür verwende ich: Firestore Go Client

  2. Ich möchte meine Dokumente nach date 创建/更新日期 sortieren können, also speichere ich je nach Dokument diese beiden Felder als Zeitstempel im Dokument.

  3. Ich verwende das Etikett servertimestamp auf beiden Feldern. Dabei sollte der Wert die Zeit sein, die der Firestore-Server benötigt hat, um die Anfrage zu verarbeiten.

  4. Die http-Antwort für den Aktualisierungsvorgang sollte den folgenden Text enthalten:

{
 "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"
 }
}

Das bedeutet, dass nach dem Aktualisieren des Ticketdokuments nichts anderes als der Wert des aktualisierten Feldes title 或 price 之外,我还需要更新 date_updated angezeigt wird.

Im Moment funktioniert es, aber ich bin gespannt, ob die Art und Weise, wie ich programmiere, dafür geeignet ist. Wie Sie im Codebeispiel sehen können, verwende ich eine Transaktion, um das Ticket zu aktualisieren. Ich finde keine andere Möglichkeit, den aktualisierten Wert des Felds dateupdated abzurufen, als das aktualisierte Ticket erneut zu lesen.

Domänenentitäten sind wie folgt definiert:

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
    }

)

Ich werde die Kommunikation mit Firestore aus der Perspektive der Erstellung und Aktualisierung hier anhängen:

// 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,
    }
}

Workaround

Wenn ich das richtig verstehe, ist das DateUpdated-Feld ein serverseitiger Zeitstempel, was bedeutet, dass sein Wert vom Server bestimmt wird, wenn er den Wert in die Speicherschicht schreibt (sog. Feldtransformation). Da ein Schreibvorgang im Firestore SDK nicht die Ergebnisdaten des Vorgangs zurückgibt, besteht die einzige Möglichkeit, diesen Wert wieder in die Anwendung zu übertragen, darin, nach dem Schreibvorgang einen zusätzlichen Lesevorgang durchzuführen, um ihn abzurufen.

Das SDK führt diesen Lesevorgang nicht automatisch durch, da es sich um einen kostenpflichtigen Vorgang handelt, der in vielen Fällen nicht benötigt wird. Indem Sie Ihren Code diesen Lesevorgang durchführen lassen, können Sie entscheiden, ob Ihnen diese Kosten entstehen.

Das obige ist der detaillierte Inhalt vonBenötige ich einen zusätzlichen Roundtrip zum Firestore, um die erstellten und aktualisierten Zeitstempelfelder zu lesen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen