Retrieve only specific Property with the Key in google-cloud datastore using golang - go

My Kind has 3 entities: FirstName, FamilyName and Email.I want to retrieve only the Key and the FirstName associated with the entity. Like this in SQL : SELECT Id,FirstName from users;
In go-lang, I tried fetching all the data in the Kind like this
q := datastore.NewQuery(dataKind)
and then to get the keys, I do this:
keys, err := q.GetAll(ctx, &users)
I don't want to fetch all the properties, instead only the keys and the FirstName. I was wondering if there is a way to do it in a single datastore query? As mentioned earlier in my previous question, I'm new to go-lang and datastore. Please help

Use Project to select a single property. The property must be indexed. The query does not return entities where the property is not set.
The following snippet returns the keys and users with only the FristName field set:
q := datastore.NewQuery(dataKind).Project("FirstName")
keys, err := client.GetAll(ctx, q, &users)

Related

How to read from Datastore using an Ancestor query and latest golang libraries

I want to read all entities from a Datastore kind (around 6 entities/records).
I have a Datastore that is key'ed on a weird type that I am trying to understand. I can't find any uniqueness on the a key to perform a query on.
The table looks like this:
GCP Datastore representing data I want to read into my Go app
When I click on a record, it looks like this:
Key literal exposed and used from here on out to try and get the records in the Go app
``I can perform an ancestor query in the console like this:```
GCP Datastore queried using Ancestor query
Great! So now I want to retrieve this data from my Golang App? But how?
I see a lot of solutions online about using q.Get(...) // where q is a *Query struct
Any of these solutions won't work because they import google.golang.org/appengine/datastore. I understand that this is legacy and deprecated. So I want a solution that imports cloud.google.com/go/datastore.
I tried something along these lines but didn't get much luck:
First try using GetAll and query
I tried this next:
Second try attempting to use ancestor query... not ready yet
Lastly I tried to get a single record directly:
Lastly I tried to get the record directly
In all cases, my err is not nil and the dts that should be populated from datastore query is also nil.
Any guidance to help me understand how to query on this key type? Am I missing something fundamental with the way this table is key'ed and queried?
Thank you
Then I tried this:
It seems you are just missing your Namespace
// Merchant Struct
type MerchantDetails struct {
MEID string
LinkTo *datastore.Key
Title string
}
// Struct array to store in
var tokens []MerchantDetails
// Ancestor Key to filter by
parentKey := datastore.NameKey("A1_1113", "activate", nil)
parentKey.Namespace = "Devs1"
// The call using the new datastore UI. Basically query.Run(), but datastore.GetAll()
keys, err := helpers.DatastoreClient.GetAll(
helpers.Ctx,
datastore.NewQuery("A1_1112").Ancestor(parentKey).Namespace("Devs1"),
&tokens,
)
if err != nil {
return "", err
}
// Print all name/id from the found values
fmt.Printf("keys: %v", keys)

Save is trying to update created_at column

We are updating our project from v1 to v2.
When we try to update a row by providing only changed fields as a struct, it tries to set created_at column and returns an error. This was working back in v1. According to documentation, during update operations, fields with default values are ignored.
err := r.writeDB.Save(&Record{
Model: Model{
ID: 1,
},
Name: "AB",
}).Error
if err != nil {
return err
}
Generates the following SQL statement
[3.171ms] [rows:0] UPDATE `records` SET `created_at`='0000-00-00 00:00:00',`updated_at`='2020-11-12 15:38:36.285',`name`='AB' WHERE `id` = 1
Returns following error
Error 1292: Incorrect datetime value: '0000-00-00' for column
'created_at' at row 1
With these entities
type Model struct {
ID int `gorm:"primary_key,type:INT;not null;AUTO_INCREMENT"`
CreatedAt time.Time `gorm:"type:TIMESTAMP(6)"`
UpdatedAt time.Time `gorm:"type:TIMESTAMP(6)"`
}
type Record struct {
Model
Name string
Details string
}
There is DB.Omit which allows ignoring a column when executing an update query. But this requires a lot of refactoring in the codebase. Does the behavior changed or is there something missing?
This might help you. Change the structure field (or add to replace default gorm.Model field) like this:
CreatedAt time.Time `gorm:"<-:create"` // allow read and create, but don't update
This tag helps to save created data from update.
In Gorm v2 Save(..) writes all fields to the database. As the CreatedAt field is the zero value, this is written to the database.
For you code to work, you can use a map:
err := r.writeDB.Model(&Record{Model:Model{ID:1}}).Update("name","AB").Error
Another option is to not fill in the Record struct, but just point to the table and use a Where clause:
err := r.writeDB.Model(&Record{}).Where("id = ?", 1).Update("name","AB").Error
If you have multiple updates you can use Updates(...) with a map, see here: https://gorm.io/docs/update.html
I was able to work around this problem using Omit() before save. Like this:
result := r.db.Omit("created_at").Save(item)
It omits the CreatedAt from the resulting update query, and updates everything else.

How to execute raw queries using sqlx?

Using sqlx as my database adapter, I'd like to run queries on user profiles based on user-submitted POST data. There are several parameters like age, sex and location and many more.
So for example if only age value is submitted by the user, the query should looks like:
var profiles []model.Profile
q:= "SELECT * FROM profile WHERE age = ?"
err = database.SQL.Select(&profiles, q, age)
if err != nil {
log.Println(err)
}
As you can see, since the query can not be built dynamically, this method is not flexible enough and becomes so verbose to account for all possible variations.
What I want is to construct query based on the input data then just feed the raw query to sqlx.
Something like this pseudo code:
q:= `SELECT * FROM profile WHERE
age > 25 AND sex="f" AND location="London"`
err = database.SQL.ExecRaw(&profiles, q)
How can I achieve this in sqlx?
I have looked at the docs but could not figure out how to do so.
If you don't want to use parameters, don't use parameters. Select doesn't prevent you from putting literals in your query.

Unique email in Google Datastore

I have a User entity containing an Email field. The User entity id is a ULID, because I want to allow users to change their email addresses, but I want to ensure that the email address is unique on both a CREATE and an UPDATE.
I am using Datastore transactions. This is a code fragment:
ctx := context.Background()
k := datastore.NameKey("User", user.ID, nil)
_, err := client.RunInTransaction(ctx, func(t *datastore.Transaction) error {
// other stuff that needs to be in transaction
_, err = t.Put(k, user)
return err
})
return err
The Email field is indexed. Is there any way to search the User entity for the current user's email address as part of the transaction?
*datastore.Transaction does not have a GetAll method, so I cannot run a query like this:
datastore.NewQuery("User").Filter("Email =", user.Email)
I'm afraid that using
client.GetAll(ctx, q, nil)
will not guarantee isolation within the transaction.
The short answer is no, you cannot use a query as part of a transaction unless you are querying a specific entity group. Global queries are alway eventually consistent. However, to put everything in a single entity group would likely limit write throughput too much.
A workaround is you can have another Kind with entities that map email addresses to users. Then you can, in a transaction, check the email Entity and if it doesn't exist or it points to a bad location, set the email Entity and the user Entity all as a single transaction.

How to search for a specific value in Firebase using Golang?

I am using Golang and Firego for connecting to Firebase. I am trying to search an admin with Email: john#gmail.com. The following is my Database Structure
For this I have tried:
dB.Child("CompanyAdmins").Child("Info").OrderBy("Email").EqualTo("john#gmail.com").Value(&result)
but it does not produce expected result. How can I do this?
While #dev.bmax has the problem identified correctly, the solution is simpler. You can specify the path of a property to order on:
dB.Child("CompanyAdmins")
.OrderBy("Info/Email")
.EqualTo("john#gmail.com")
.Value(&result)
Update (2017-02-10):
Full code I just tried:
f := firego.New("https://stackoverflow.firebaseio.com", nil)
var result map[string]interface{}
if err := f.Child("42134844/CompanyAdmins").OrderBy("Info/Email").EqualTo("john#gmail.com").Value(&result); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", result)
This prints:
map[-K111111:map[Info:map[Email:john#gmail.com]]]
Which is the exact place where I put the data.
Update 20170213:
This is the index I have defined:
"CompanyAdmins": {
".indexOn": "Info/Email"
}
If this doesn't work for you, please provide a similarly complete snippet that I can test.
Can you put Info data directly into CompanyAdmins structure? This way, your query will work.
CompanyAdmins
-id
-Email: "johndon#gmail.com"
-Settings:
- fields
The problem with your query, is that Info is not a direct child of CompanyAdmins.
You could use the email as the key instead of an auto-generated one when you insert values. That way, you can access the admin directly:
dB.Child("CompanyAdmins").Child("john#gmail.com").Child("Info")
Otherwise, you need to restructure the database. Your order-by field (email) should be one level higher, like Rodrigo Vinicius suggests. Then, your query will change to:
dB.Child("CompanyAdmins").OrderBy("Email").EqualTo("john#gmail.com")

Resources