google-cloud-go
google-cloud-go copied to clipboard
datastore: WithIgnoreFieldMismatch option works for just first record in embedded / nested struct array case.
Current Behavior When using WithIgnoreFieldMismatch option, I cannot retrieve after second records in embedded / nested struct array case, and always need to implement Loader / Saver methods per a entity also workaround to ignore the error ErrFieldMismatch in Loader method.
Requested Behavior Please enhance WithIgnoreFieldMismatch option behavior to retrieve all records even in embedded / nested struct array case.
Reproduced Code Please confirm following code behavior like following 3 steps.
- Uncomment CASE1 field and code and run the code. Note that you can retrieve 2 records.
- Undo the step1 uncomments and run the code. Note that you can only retrieve 1 record.
- Uncomment CASE OPT code and use known workaround. Note that you can retrieve 2 records.
package main
import (
"context"
"log"
"os"
"cloud.google.com/go/datastore"
)
type Tier1 struct {
Tier1Field string
Tier2 []*Tier2
}
type Tier2 struct {
Tier2Field1 string
// CASE1: First time, uncomment / enable following field to put the data and retrieve it correctly.
// CASE2: Second time, undo / comment out following field to reproduct the issue.
//Tier2Field2 string
}
func (entity *Tier2) Load(p []datastore.Property) error {
return datastore.LoadStruct(entity, p)
// CASE OPTION: We know that this workaround works regardless WithIgnoreFieldMismatch option use.
/*
err := datastore.LoadStruct(entity, p)
if fmerr, ok := err.(*datastore.ErrFieldMismatch); ok && fmerr != nil {
err = nil
}
return err
*/
}
func (entity *Tier2) Save() ([]datastore.Property, error) {
return datastore.SaveStruct(entity)
}
func main() {
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "menu4today-850612-eb5fb6a47e42.json")
ctx := context.Background()
client, err := datastore.NewClient(ctx, "menu4today-850612", datastore.WithIgnoreFieldMismatch())
if err != nil {
panic(err)
}
key := datastore.NameKey("TempEntity", "test", nil)
// CASE1: First time, use following code to put the data and retrieve it correctly.
// CASE2: Second time, undo / comment out following code to reproduct the issue.
/*
newEntity := &Tier1{
Tier1Field: "tier1",
Tier2: []*Tier2{
{
Tier2Field1: "tier2-1-1",
Tier2Field2: "tier2-1-2",
},
{
Tier2Field1: "tier2-2-1",
Tier2Field2: "tier2-2-2",
},
},
}
if _, err := client.Put(ctx, key, newEntity); err != nil {
log.Fatalf("Failed to put entity: %v", err)
}
fmt.Println("Entity saved successfully")
*/
var retrievedEntity Tier1
if err := client.Get(ctx, key, &retrievedEntity); err != nil {
log.Fatalf("Failed to get entity: %v", err)
}
// CASE1: The result is to get 2 records.
// CASE2: The result is to get only 1 record.
// CASE OPT: The result is to get 2 records.
println(len(retrievedEntity.Tier2))
}
My go.mod
module test-ds
go 1.23.0
require (
cloud.google.com/go/datastore v1.18.0
)
Working on it but reducing the priority since there is a workaround