Unique email in Google Datastore - go

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.

Related

Go GORM two table requests

So I am new to GORM and I have this task where I have two tables accounts and users
I get the user.Id and I need to get the accountId from the user table afterwards I need to only get the account that has the same Id as user.AccountId
type User struct{
Id int
AccountId int
}
type Account struct{
Id int
Balance int
}
It looks like this should be a pretty simple call to do it in a single request, but I can't find a simple implementation for this logic. Can anyone help me
There are multiple ways to do this, and below are a couple of them. I'm assuming that the db variable is of type *gorm.DB. Also, I'm the code below is suited for MySQL (minor changes are needed for PostgreSQL).
Load just the Account data with joins
var account Account
err := db.Joins("JOIN users ON users.account_id = account.id").Where("users.id = ?", user.Id).First(&account).Error
Load the User object with the Account data
Here there are a few changes to the User struct, but the underlying code is simpler. Also, it loads the entire User object, with the related Account object.
type User struct{
Id int
AccountId int
Account Account
}
var fullUser User
err := db.Preload("Account").First(&fullUser, user.Id).Error

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)

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

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)

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")

golang gorp insert multiple records

Using gorp how can one insert multiple records efficiently? i.e instead of inserting one at a time, is there a batch insert?
var User struct {
Name string
Email string
Phone string
}
var users []Users
users = buildUsers()
dbMap.Insert(users...) //this fails compilation
//I am forced to loop over users and insert one user at a time. Error Handling omitted for brevity
Is there a better mechanism with gorp? Driver is MySQL.
As I found out on some other resource the reason this doesn't work is that interface{} and User{} do not have the same layout in memory, therefore their slices aren't of compatible types. Suggested solution was to convert []User{} into []interface{} in for loop, like shown here: https://golang.org/doc/faq#convert_slice_of_interface
There is still on caveat: you need to use pointers for DbMap.Insert()function.
Here's how I solved it:
s := make([]interface{}, len(users))
for i, v := range users {
s[i] = &v
}
err := dbMap.Insert(s...)
Note that &v is important, otherwise Insert will complain about non-pointers.
It doesn't look like gorp has anything that gives a wrapper for either raw SQL or multi value inserts (which is always SQL dialect dependent).
Are you worried about speed or transactions? If not, I would just do the inserts in a for loop.

Resources