在golang中使用datastore.GetAll没有得到结果。

huangapple go评论79阅读模式
英文:

Not getting results with datastore.GetAll in golang

问题

我有两个函数:一个用于将实体写入数据存储,另一个用于检索它们。当我在检索中使用datastore.GetAll()函数时,它返回的结果为空。我有一个测试来验证写入似乎正常工作。有什么想法为什么检索不起作用?

以下是应用程序代码:

package tracker

import (
   "fmt"
    
   "appengine"
   "appengine/datastore"
)

type User struct {
    Email string
}

func createUser(ctx appengine.Context, email string) (*datastore.Key, error) {
    u := &User{
        Email: email,
        }
    incompleteKey := datastore.NewIncompleteKey(ctx, "User", nil)
    key, err := datastore.Put(ctx, incompleteKey, u)
    if err != nil {
        return key, err
    }

    return key, nil
}

func getUser(ctx appengine.Context, email string) (u *User, e error) {
    users := []User{}
    q := datastore.NewQuery("User").Filter("Email =", email)
    keys, err := q.GetAll(ctx, &users)
    if err != nil {
        return nil, err
    }
    fmt.Printf("KEYS: %v", keys)
    return &users[0], nil
}

以下是测试代码:

package tracker

import (
    "fmt"
    "testing"
    
    "appengine/datastore"
    "appengine/aetest"
)

// This test is passing.
func TestCreateUser(t *testing.T) {
    ctx, err := aetest.NewContext(nil)
    if err != nil {
        t.Fatal(err)
    }
    defer ctx.Close()

    email := "testing@testing.go"
    newKey, err := createUser(ctx, email)
    if err != nil {
        t.Errorf("Failed to create a new user: %v", err)
    }

    u := User{}
    datastore.Get(ctx, newKey, &u)

    if u.Email != email {
        t.Errorf("Expected email to be %s, found %v.", email, u.Email)
    }
}

func TestGetUser(t *testing.T) {
    ctx, err := aetest.NewContext(nil)
    if err != nil {
        t.Fatal(err)
    }
    defer ctx.Close()

    email := "testing@testing.go"
    newKey, err := createUser(ctx, email)
    fmt.Printf("key, %v; ", newKey)
    u, err := getUser(ctx, email)
    fmt.Printf("user, %v; error: %s", u, err)

    if u.Email != email {
        t.Error("Expected email to be %s, found %v.", email, u.Email)
    }
}

希望这可以帮助你解决问题。

英文:

I have two functions: one which writes entities to datastore and the other is suppose to retrieve them. When I use datastore.GetAll() function in my retrieval it returns no results. I do have a test that verifies that the writing seems to be working correctly. Any ideas as to why retrieval isn't working?

Here is the application code:

package tracker

import (
   "fmt"
    
   "appengine"
   "appengine/datastore"
)

type User struct {
    Email string
}

func createUser(ctx appengine.Context, email string) (*datastore.Key, error) {
    u := &User{
        Email: email,
        }
    incompleteKey := datastore.NewIncompleteKey(ctx, "User", nil)
    key, err := datastore.Put(ctx, incompleteKey, u)
    if err != nil {
        return key, err
    }

    return key, nil
}

func getUser(ctx appengine.Context, email string) (u *User, e error) {
    users := []User{}
    q := datastore.NewQuery("User").Filter("Email", email)
    keys, err := q.GetAll(ctx, &users)
    if err != nil {
        return nil, err
    }
    fmt.Printf("KEYS: %v", keys)
    return &users[0], nil
}

Here is the test code:

package tracker

import (
    "fmt"
    "testing"
    
    "appengine/datastore"
    "appengine/aetest"
)

// This test is passing.
func TestCreateUser(t *testing.T) {
    ctx, err := aetest.NewContext(nil)
    if err != nil {
        t.Fatal(err)
    }
    defer ctx.Close()

    email := "testing@testing.go"
    newKey, err := createUser(ctx, email)
    if err != nil {
        t.Errorf("Failed to create a new user: %v", err)
    }

    u := User{}
    datastore.Get(ctx, newKey, &u)

    if u.Email != email {
        t.Errorf("Expected email to be %s, found %v.", email, u.Email)
    }
}

func TestGetUser(t *testing.T) {
    ctx, err := aetest.NewContext(nil)
    if err != nil {
        t.Fatal(err)
    }
    defer ctx.Close()

    email := "testing@testing.go"
    newKey, err := createUser(ctx, email)
    fmt.Printf("key, %v; ", newKey)
    u, err := getUser(ctx, newKey)
    fmt.Printf("user, %v; error: %s", u, err)

    if u.Email != email {
        t.Error("Expected email to be %s, found %v.", email, u.Email)
    }
}

答案1

得分: 5

datastore.GetAll()不会立即返回结果,因为在该查询中应用了最终一致性。SDK模拟了最终一致性,并不会立即返回新保存的实体。

但是在你的TestCreateUser()方法中,当你使用datastore.Get()时,即使实体是新保存的("刚刚"保存的),它也会返回给你,因为这是通过键进行查找,而键是强一致性的。

背后发生的情况是,当你调用datastore.Put()时,实体数据(属性的值)被保存,其键被索引,然后datastore.Put()返回,并且其他属性和复合索引的索引会在后台异步更新。因此,如果你尝试执行使用索引查找/列出实体的查询(你正在通过Email属性查询),该查询在正确索引之前将不会看到(包含)新实体。当你使用datastore.Get()时,它通过键加载实体,而不是通过其他(非键属性或复合)索引加载实体,因此通过键获取实体将立即看到新实体(在datastore.Put()返回之后)。

如果你想在本地环境中进行测试,可以在创建用于创建新上下文的实例时提供StronglyConsistentDatastore选项,如下所示:

inst, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
    t.Fatalf("Failed to create instance: %v", err)
}
defer inst.Close()

req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
    t.Fatalf("Failed to create req: %v", err)
}
ctx := appengine.NewContext(req)

还要注意,如果你使用了延迟(例如time.Sleep(time.Millisecond * 500)),datastore.GetAll()也会返回新实体,但上述选项是测试的正确方式。

有许多类似的问题(+答案),可以阅读它们以获取更多详细信息:

https://stackoverflow.com/questions/28590519/google-app-engine-datastore-testing-queries-fails

https://stackoverflow.com/questions/29228712/how-to-filter-a-gae-query

https://stackoverflow.com/questions/30503343/google-app-engine-datastore-query-with-cursor-wont-iterate-all-items

英文:

datastore.GetAll() doesn't return result to you because with that query eventual consistency applies. The SDK simulates the eventual consistency and doesn't return you the newly saved entities immediately.

But in your TestCreateUser() method when you use datastore.Get(), that will return you the entity even if it was newly ("just now") saved, because it's a lookup by a key, and they are strongly consistent.

What happens behind the scenes is that when you call datastore.Put(), the entity data (values of properties) is saved and its key is indexed, then datastore.Put() returns, and indices of other properties and composite indices are updated asynchronously "in the background". So if you try to execute a query that uses an index to find/list entities (you were querying by the Email property), that query will not see (will not include) new entities until they are properly indexed. When you do a datastore.Get(), that loads the entity by its key and not by other (non-key property or composite) indices, so getting an entity by key will see the new entity "immediately" (after datastore.Put() has returned).

If you want to test this in local environment, you may provide StronglyConsistentDatastore option when creating the instance that will be used to create a new context, like this:

inst, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
	t.Fatalf("Failed to create instance: %v", err)
}
defer inst.Close()

req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
	t.Fatalf("Failed to create req: %v", err)
}
ctx := appengine.NewContext(req)

Also note that if you use a sleep (e.g. time.Sleep(time.Millisecond * 500)), datastore.GetAll() will also return the new entity, but the above option is the proper way to test this.

There are numerous similar questions (+answers), read them for more details:

https://stackoverflow.com/questions/28590519/google-app-engine-datastore-testing-queries-fails

https://stackoverflow.com/questions/29228712/how-to-filter-a-gae-query

https://stackoverflow.com/questions/30503343/google-app-engine-datastore-query-with-cursor-wont-iterate-all-items

huangapple
  • 本文由 发表于 2016年4月16日 01:05:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/36653013.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定