首页 > 解决方案 > 类型与 []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)
    }
}

标签: gogoogle-cloud-datastore

解决方案


为了理解为什么这适用于普通查询而不是投影查询,您可能需要首先了解这两者之间的实际区别是什么。正如这篇文章中提到的:

而针对 Cloud Datastore 的“常规”(我理解为 SELECT * ...)查询通常使用仅包含查询实体属性的排序子集以及指向完整实体的指针的索引,而投影查询则针对包含查询请求的所有字段的索引。因此,一旦通过索引识别出与查询匹配的实体集,就不再需要获取查询的实体,因此显着的延迟增益似乎来自于此。

因此,基本上,当您进行投影查询时,不会获取您查询的实体。

当我阅读这份官方文档时,我发现了一些与您的问题相关的非常有趣的短语:

切片类型的字段对应于 Datastore 数组属性,但 []byte 除外,它对应于 Datastore blob。如果将非数组值加载到切片字段中,则结果将是具有一个元素的切片,其中包含该值。

关键字段 如果结构包含带有名称“ key ”标记的 *datastore.Key 字段,则在 Put 上将忽略其值。将实体读回 Go 结构时,该字段将填充用于查询实体的 *datastore.Key 值。

我从这里了解到的是,也许在您的情况下,字段中填充了该查询的键值( string )。

我发现的另一个有趣的事情是,根据属性和值类型文档,类型 []byte 没有被索引。正如这里所说,未索引的属性不能被投影。因此,预计的查询根本不应该适用于这个特定的用例。


推荐阅读