This is a GoLang, Firebase AdminSDK question.
This example works to iterate through all of the documents in a FireStore DB.
How can I get the Document Name?
To put another way: If the collection name is JohnyCollection, and JohnyCollection has 20 Documents called (Document1, Document2.... Document20), how do I get the document name in golang Code?
//========================================
package main
import (
"context"
"fmt"
"log"
"firebase.google.com/go"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
ctx := context.Background()
sa := option.WithCredentialsFile("./scai-qit-fb-adminsdk.json")
app, err := firebase.NewApp(ctx, nil, sa)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
client, err := app.Firestore(ctx)
if err != nil {
log.Fatal(err)
}
defer client.Close()
iter := client.Collection("COMPLEX_NONACS").Documents(ctx)
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate: %v", err)
}
//This part works. WIll return a Map of each Document
fmt.Println("--------------------------/n")
fmt.Println(doc.Data())
// This is the question. How do I get the INDEX name of the Document?
// something like...
fmt.Println(doc.Index_value_or_something_that_returns_IndexName())
// for example...
// {
// "ABC":{"line1":"yabba dabba","line2":"dingo dong"},
// "DEF":{"line1":"hooty tooty","line2":"blah blah"}
// }
// How to just get the "ABC" and "DEF"
}
}
You can get the document ID from the DocumentSnapshot, by first looking up the DocumentRef:
fmt.Println(doc.Ref.ID)
See the reference docs for DocumentSnapshot and DocumentRef.
Related
In the following codes, s.getFile gets file from S3 and return a struct of io.ReadCloser and ContentLength.
WriteResultesponse write the file to http.ResponseWriter.
But *reader.ContentLength sometimes is different from actualContentLength.
Any idea why? Thanks
s3Ctx, closeS3 := context.WithTimeout(ctx, xxx) // 1 hour
defer closeS3()
// directly stream result from locations
for _, location := range Locations {
reader, err := s.getFile(s3Ctx, xxx)
// reader is
//struct {
// Data io.ReadCloser
// ContentLength *int64
//}
if err != nil {
return err
}
actualContentLength, err := WriteResultesponse(params.Writer, ResultResponse{
Data: reader.Data,
})
}
// WriteResultResponse streams the result data to the user.
func WriteResultResponse(w http.ResponseWriter, resultResp ResultResponse) (int64, error) {
w.Header().Set("Content-Type", "text/plain")
// resultResp.Data is io.ReadCloser
defer resultResp.Data.Close()
return io.Copy(w, resultResp.Data)
}
UPDATE
How about
if f, ok := params.Writer.(http.Flusher); ok {
f.Flush()
}
?
I'm trying to find a more efficient way to iterate over a collection with its subcollections in firestore with go than a nested for loop. I have a collection called Place with a subcollection Ticket.
These are the two structs that I'm working with:
type Place struct {
PlaceName string `json:"placeName"`
PlaceLocation string `json:"placeLocation"`
PhoneNumber string `json:"phoneNumber"`
NumTickets []Ticket `json:"numTickets"`
}
type Ticket struct {
TicketType string `json:"ticketType"`
NumberTicketsAvail int64 `json:"numberTicketsAvail"`
}
And, here's the piece of code that I have at the moment:
func (*repo) FindAll() ([]entity.Place, error) {
ctx := context.Background()
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create a firestore client: %v", err)
return nil, err
}
defer client.Close()
var places []entity.Place
it := client.Collection(collectionName).Documents(ctx)
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate: %v", err)
return nil, err
}
ticketRef := doc.Ref.Collection("Ticket")
var tickets []entity.Ticket
it := ticketRef.Documents(ctx)
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate over tickets: %v", err)
return nil, err
}
ticket := entity.Ticket{
TicketType: doc.Data()["TicketType"].(string),
NumberTicketsAvail: doc.Data()["NumberTicketsAvail"].(int64),
}
tickets = append(tickets, ticket)
}
place := entity.Place{
PlaceName: doc.Data()["PlaceName"].(string),
PlaceLocation: doc.Data()["PlaceLocation"].(string),
PhoneNumber: doc.Data()["PhoneNumber"].(string),
NumTickets: tickets,
}
places = append(places, place)
}
return places, nil
}
This is a stripped-down version of the code I want to use for a page-specific web crawler. The idea is to have a function that gets a URL, deals with HTTP and returns a Reader to the response body http.Response:
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
const url = "https://xkcd.com/"
r, err := getPageContent(url)
if err != nil {
log.Fatal(err)
}
f, err := os.Create("out.html")
if err != nil {
log.Fatal(err)
}
defer f.Close()
io.Copy(f, r)
}
func getPageContent(url string) (io.Reader, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
return res.Body, nil
}
The response body is never closed, which is bad. Closing it inside of the getPageContent function won't work, of course, for io.Copy won't be able to read anything from a closed resource.
My question is rather of general interest than for the specific use case: How can I use functions to abstract the gathering of external resources without having to store the whole resource in a temporary buffer? Or should I better avoid such abstractions?
As pointed out by the user leaf bebop in the comment section, the function getPageCount should return an io.ReadCloser instead of just an io.Reader:
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
const url = "https://xkcd.com/"
r, err := getPageContent(url)
if err != nil {
log.Fatal(err)
}
defer r.Close()
f, err := os.Create("out.html")
if err != nil {
log.Fatal(err)
}
defer f.Close()
io.Copy(f, r)
}
func getPageContent(url string) (io.ReadCloser, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
return res.Body, nil
}
Another solution is you can directly return the response and close it in main function. In general you can put checks on response StatusCode etc. if new requirements come. Here is the updated code:
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
const url = "https://xkcd.com/"
r, err := getPageContent(url)
if err != nil {
log.Fatal(err)
}
defer r.Body.Close()
if r.StatusCode !=http.StatusOK{
//some operations
}
f, err := os.Create("out.html")
if err != nil {
log.Fatal(err)
}
defer f.Close()
io.Copy(f, r.Body)
}
func getPageContent(url string) (*http.Response, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
return res, nil
}
I am using golang and firego for connecting to Firebase. I want to update my data Statusfrom ON to OFF with key IDAgent: 7. This is my Database Structure
Image
Assumption : I don't know child active_chat. How can i update data in active_chat/-Koja8GuFplEN3kjbfPO where IDAgent = 7
I have tried this code
x := map[string]string{"Status": "OFF"}
ref.OrderBy("IDAgent").EqualTo("7").Update(x)
but this code wrong query.
In two ways you can do, as per Firebase doc with firego client library. Drafted answer based on from firego README.md.
Note: You have not provided the complete path of the structure, I have drafted the answer based on screenshot. So update your JSON path accordingly.
Approach 1:
f := firego.New("https://my-firebase-app.firebaseIO.com/active-chat/Koja8GuFpIEN3kjbfPO.json", nil)
x := map[string]string{
"Status": "OFF",
}
if err := f.Update(x); err != nil {
log.Fatal(err)
}
Approach 2:
f := firego.New("https://my-firebase-app.firebaseIO.com", nil)
f = f.Ref("/active-chat/Koja8GuFpIEN3kjbfPO.json")
x := map[string]string{
"Status": "OFF",
}
if err := f.Update(x); err != nil {
log.Fatal(err)
}
Update for 2022:
package main
import (
"context"
"fmt"
"time"
firestore "cloud.google.com/go/firestore"
firebase "firebase.google.com/go"
"google.golang.org/api/option"
)
type (
myDocument struct {
Cars []Car `firestore:"cars"`
carsCount int64 `firestore:"car_count"`
UpdateTime string `firestore:"update_time"`
}
Car struct {
Name string `firestore:"name"`
YearBuilt string `firestore:"year_built"`
}
)
func getFirebaseClient(ctx context.Context) (*firestore.Client, error) {
sa := option.WithCredentialsFile("Path_To_Firebase_Key")
// Initialize firebase app with admin privileges
app, err := firebase.NewApp(ctx, nil, sa)
if err != nil {
err = fmt.Errorf("getFirestoreClient failed: %s", err)
return nil, err
}
// Create client
client, err := app.Firestore(ctx)
if err != nil {
err = fmt.Errorf("failed to connect to firestore: %v", err)
return nil, err
}
return client, nil
}
func main() {
// Create context
ctx := context.Background()
// Get firebase client
client, err := getFirebaseClient(ctx)
if err != nil {
panic(err)
}
// Create car struct
newCar := Car{
"Volvo_Series1",
"1920",
}
// Update time
newTime := time.Now().UTC().Format("Monday, 01-02-2006 15:04:05")
// Updates to document
updates := []firestore.Update{
{Path: "cars", Value: firestore.ArrayUnion(newCar)},
{Path: "car_count", Value: firestore.Increment(1)},
{Path: "update_date", Value: newTime},
}
// OPTION A)
// Create collection reference
collectionRef := client.Collection("cars")
// Create document reference
docRef := collectionRef.Doc("12345")
// Update document
_, err = docRef.Update(ctx, updates)
if err != nil {
err := fmt.Errorf("failed updating document: %s from %s collection %v", docRef.ID, docRef.Parent.ID, err)
panic(err)
}
// OPTION B)
_, err = client.Collection("cars").Doc("12345").Update(ctx, updates)
if err != nil {
err := fmt.Errorf("failed updating document: %s from %s collection %v", docRef.ID, docRef.Parent.ID, err)
panic(err)
}
}
So I have a function getToken()
func getToken() jwt.MapClaims {
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkYW0iLCJwYXNzd29yZCI6InRlc3QiLCJpYXQiOjE0ODcyMDY2OTIsImV4cCI6MTUxODc2NDI5Mn0.6LQo_gRwXiFBvNIJOwtf9UuxoQMZZ3XNILTnU-46-Zg"
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
hmacSampleSecret := []byte("supersecretkittysecret")
return hmacSampleSecret, nil
})
if err != nil {
println("error")
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims
} else {
return nil
}
}
Then the corresponding call:
res := getToken()
println(res["username"])
Why is res["username"] equal to two memory addresses (0x2b3c20,0xc420075420)? This should just be a string like adam. I have also tried func getToken() *jwt.MapClaims and return &claims, but this still did not help.
You should try using fmt.Println instead of println. Here's an example of printing a map using println vs fmt.Println
package main
import (
"fmt"
)
func foo() map[string]string {
return map[string]string{
"k": "value",
}
}
func main() {
res := foo()
println("Output from println:", res) // prints pointer address
fmt.Println("Output from fmt.Println: ", res) // prints the map
}
https://play.golang.org/p/gCNqng3KEE
Output:
Output from println: 0x10432200
Output from fmt.Println: map[k:value]