| // Copyright 2017 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // DO NOT EDIT doc.go. Modify internal/doc.template, then run make -C internal. |
| |
| /* |
| Package firestore provides a client for reading and writing to a Cloud Firestore |
| database. |
| |
| See https://cloud.google.com/firestore/docs for an introduction |
| to Cloud Firestore and additional help on using the Firestore API. |
| |
| See https://godoc.org/cloud.google.com/go for authentication, timeouts, |
| connection pooling and similar aspects of this package. |
| |
| Note: you can't use both Cloud Firestore and Cloud Datastore in the same |
| project. |
| |
| # Creating a Client |
| |
| To start working with this package, create a client with a project ID: |
| |
| ctx := context.Background() |
| client, err := firestore.NewClient(ctx, "projectID") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| # CollectionRefs and DocumentRefs |
| |
| In Firestore, documents are sets of key-value pairs, and collections are groups of |
| documents. A Firestore database consists of a hierarchy of alternating collections |
| and documents, referred to by slash-separated paths like |
| "States/California/Cities/SanFrancisco". |
| |
| This client is built around references to collections and documents. CollectionRefs |
| and DocumentRefs are lightweight values that refer to the corresponding database |
| entities. Creating a ref does not involve any network traffic. |
| |
| states := client.Collection("States") |
| ny := states.Doc("NewYork") |
| // Or, in a single call: |
| ny = client.Doc("States/NewYork") |
| |
| # Reading |
| |
| Use DocumentRef.Get to read a document. The result is a DocumentSnapshot. |
| Call its Data method to obtain the entire document contents as a map. |
| |
| docsnap, err := ny.Get(ctx) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| dataMap := docsnap.Data() |
| fmt.Println(dataMap) |
| |
| You can also obtain a single field with DataAt, or extract the data into a struct |
| with DataTo. With the type definition |
| |
| type State struct { |
| Capital string `firestore:"capital"` |
| Population float64 `firestore:"pop"` // in millions |
| } |
| |
| we can extract the document's data into a value of type State: |
| |
| var nyData State |
| if err := docsnap.DataTo(&nyData); err != nil { |
| // TODO: Handle error. |
| } |
| |
| Note that this client supports struct tags beginning with "firestore:" that work like |
| the tags of the encoding/json package, letting you rename fields, ignore them, or |
| omit their values when empty. |
| |
| To retrieve multiple documents from their references in a single call, use |
| Client.GetAll. |
| |
| docsnaps, err := client.GetAll(ctx, []*firestore.DocumentRef{ |
| states.Doc("Wisconsin"), states.Doc("Ohio"), |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| for _, ds := range docsnaps { |
| _ = ds // TODO: Use ds. |
| } |
| |
| # Writing |
| |
| For writing individual documents, use the methods on DocumentReference. |
| Create creates a new document. |
| |
| wr, err := ny.Create(ctx, State{ |
| Capital: "Albany", |
| Population: 19.8, |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(wr) |
| |
| The first return value is a WriteResult, which contains the time |
| at which the document was updated. |
| |
| Create fails if the document exists. Another method, Set, either replaces an existing |
| document or creates a new one. |
| |
| ca := states.Doc("California") |
| _, err = ca.Set(ctx, State{ |
| Capital: "Sacramento", |
| Population: 39.14, |
| }) |
| |
| To update some fields of an existing document, use Update. It takes a list of |
| paths to update and their corresponding values. |
| |
| _, err = ca.Update(ctx, []firestore.Update{{Path: "capital", Value: "Sacramento"}}) |
| |
| Use DocumentRef.Delete to delete a document. |
| |
| _, err = ny.Delete(ctx) |
| |
| # Preconditions |
| |
| You can condition Deletes or Updates on when a document was last changed. Specify |
| these preconditions as an option to a Delete or Update method. The check and the |
| write happen atomically with a single RPC. |
| |
| docsnap, err = ca.Get(ctx) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| _, err = ca.Update(ctx, |
| []firestore.Update{{Path: "capital", Value: "Sacramento"}}, |
| firestore.LastUpdateTime(docsnap.UpdateTime)) |
| |
| Here we update a doc only if it hasn't changed since we read it. |
| You could also do this with a transaction. |
| |
| To perform multiple writes at once, use a WriteBatch. Its methods chain |
| for convenience. |
| |
| WriteBatch.Commit sends the collected writes to the server, where they happen |
| atomically. |
| |
| writeResults, err := client.Batch(). |
| Create(ny, State{Capital: "Albany"}). |
| Update(ca, []firestore.Update{{Path: "capital", Value: "Sacramento"}}). |
| Delete(client.Doc("States/WestDakota")). |
| Commit(ctx) |
| |
| # Queries |
| |
| You can use SQL to select documents from a collection. Begin with the collection, and |
| build up a query using Select, Where and other methods of Query. |
| |
| q := states.Where("pop", ">", 10).OrderBy("pop", firestore.Desc) |
| |
| Supported operators include '<', '<=', '>', '>=', '==', 'in', 'array-contains', and |
| 'array-contains-any'. |
| |
| Call the Query's Documents method to get an iterator, and use it like |
| the other Google Cloud Client iterators. |
| |
| iter := q.Documents(ctx) |
| defer iter.Stop() |
| for { |
| doc, err := iter.Next() |
| if err == iterator.Done { |
| break |
| } |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(doc.Data()) |
| } |
| |
| To get all the documents in a collection, you can use the collection itself |
| as a query. |
| |
| iter = client.Collection("States").Documents(ctx) |
| |
| # Collection Group Partition Queries |
| |
| You can partition the documents of a Collection Group allowing for smaller subqueries. |
| |
| collectionGroup = client.CollectionGroup("States") |
| partitions, err = collectionGroup.GetPartitionedQueries(ctx, 20) |
| |
| You can also Serialize/Deserialize queries making it possible to run/stream the |
| queries elsewhere; another process or machine for instance. |
| |
| queryProtos := make([][]byte, 0) |
| for _, query := range partitions { |
| protoBytes, err := query.Serialize() |
| // handle err |
| queryProtos = append(queryProtos, protoBytes) |
| ... |
| } |
| |
| for _, protoBytes := range queryProtos { |
| query, err := client.CollectionGroup("").Deserialize(protoBytes) |
| ... |
| } |
| |
| # Transactions |
| |
| Use a transaction to execute reads and writes atomically. All reads must happen |
| before any writes. Transaction creation, commit, rollback and retry are handled for |
| you by the Client.RunTransaction method; just provide a function and use the |
| read and write methods of the Transaction passed to it. |
| |
| ny := client.Doc("States/NewYork") |
| err := client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error { |
| doc, err := tx.Get(ny) // tx.Get, NOT ny.Get! |
| if err != nil { |
| return err |
| } |
| pop, err := doc.DataAt("pop") |
| if err != nil { |
| return err |
| } |
| return tx.Update(ny, []firestore.Update{{Path: "pop", Value: pop.(float64) + 0.2}}) |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| # Google Cloud Firestore Emulator |
| |
| This package supports the Cloud Firestore emulator, which is useful for testing and |
| development. Environment variables are used to indicate that Firestore traffic should be |
| directed to the emulator instead of the production Firestore service. |
| |
| To install and run the emulator and its environment variables, see the documentation |
| at https://cloud.google.com/sdk/gcloud/reference/beta/emulators/firestore/. Once the |
| emulator is running, set FIRESTORE_EMULATOR_HOST to the API endpoint. |
| |
| // Set FIRESTORE_EMULATOR_HOST environment variable. |
| err := os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:9000") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // Create client as usual. |
| client, err := firestore.NewClient(ctx, "my-project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| defer client.Close() |
| */ |
| package firestore |