go - 类型与 []byte 属性上的投影不匹配
问题描述
我有一个结构如下
type MyEntity struct {
PF []byte `json:"-" datastore:"_pf"`
}
没有投影的查询工作正常。但是,当我在“_pf”字段上使用投影进行查询时,出现“类型不匹配:字符串与 []uint8”错误。我实现了 PropertyLoadSaver 并检查了 "_pf" 属性的 prop.Value,发现有些行返回 []byte 类型和一些返回字符串。那么,为什么投影查询失败并出现此错误,而非投影查询很好?目前我正在通过实现 PropertyLoadSaver 接口并显式检查类型并将字符串类型转换为 []byte 类型来解决此问题。
这是完整的测试用例。这是在云数据存储模拟器上复制的。为下面的 datastoreProject 变量使用适当的值。其余的都应该直接工作。您可以通过插入两个实体或其中一种实体类型来查看行为。显示的错误是
panic: datastore: cannot load field "_pf" into a "tests.MyEntity": type mismatch: string versus []uint8 [recovered]
panic: datastore: cannot load field "_pf" into a "tests.MyEntity": type mismatch: string versus []uint8
以下是代码。
type MyEntity struct {
PF []byte `json:"-" datastore:"_pf"`
}
func TestPackedField(t *testing.T) {
e1 := &MyEntity{PF: []byte{83, 0, 0, 0, 93, 150, 154, 206, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3}} // returns []byte on projection
e2 := &MyEntity{PF: []byte{83, 0, 0, 0, 93, 120, 79, 87, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3}} // returns string on projection
ctx := context.Background()
conn, err := datastore.NewClient(ctx, datastoreProject)
if err != nil {
panic(err)
}
bkey := datastore.NameKey("Bytes", "bytearray", nil)
if true {
conn.Put(ctx, bkey, e1)
}
skey := datastore.NameKey("Bytes", "string", nil)
if true {
conn.Put(ctx, skey, e2)
}
q1 := datastore.NewQuery("Bytes").Order("-_pf").Limit(2)
var elfull []*MyEntity
if _, err := conn.GetAll(ctx, q1, &elfull); err != nil {
panic(err)
}
q2 := datastore.NewQuery("Bytes").Project("_pf").Order("-_pf").Limit(2)
var elprojected []*MyEntity
if _, err := conn.GetAll(ctx, q2, &elprojected); err != nil {
conn.Delete(ctx, bkey)
conn.Delete(ctx, skey)
panic(err)
}
}
解决方案
为了理解为什么这适用于普通查询而不是投影查询,您可能需要首先了解这两者之间的实际区别是什么。正如这篇文章中提到的:
而针对 Cloud Datastore 的“常规”(我理解为 SELECT * ...)查询通常使用仅包含查询实体属性的排序子集以及指向完整实体的指针的索引,而投影查询则针对包含查询请求的所有字段的索引。因此,一旦通过索引识别出与查询匹配的实体集,就不再需要获取查询的实体,因此显着的延迟增益似乎来自于此。
因此,基本上,当您进行投影查询时,不会获取您查询的实体。
当我阅读这份官方文档时,我发现了一些与您的问题相关的非常有趣的短语:
切片类型的字段对应于 Datastore 数组属性,但 []byte 除外,它对应于 Datastore blob。如果将非数组值加载到切片字段中,则结果将是具有一个元素的切片,其中包含该值。
关键字段 如果结构包含带有名称“ key ”标记的 *datastore.Key 字段,则在 Put 上将忽略其值。将实体读回 Go 结构时,该字段将填充用于查询实体的 *datastore.Key 值。
我从这里了解到的是,也许在您的情况下,字段中填充了该查询的键值( string )。
我发现的另一个有趣的事情是,根据属性和值类型文档,类型 []byte 没有被索引。正如这里所说,未索引的属性不能被投影。因此,预计的查询根本不应该适用于这个特定的用例。
推荐阅读
- algorithm - 这个三重嵌套循环的大 O 是多少?
- android - Android导航视图点击监听器不起作用
- c# - Sys.WebForms.PageRequestManagerServerErrorException:引发了“System.Web.HttpUnhandledException”类型的异常
- collections - kotlin 将此转换的结果分配给一个变量
- c++ - 在 C++ 中强制删除 std::shared_ptr
- r - 在 r 中创建带有凸包的图
- sql-server - 将 3 个表连接到一个结果集中
- reactjs - react-router-dom 中的第二个和后续路由没有被渲染?
- excel - Excel VBA 代码,用于在一个单元格中进行多项选择的数据验证 - 用于多列
- xml - 使用 XML 和 XSL 创建 SVG 折线图