在Go中从Python项目中加载数据存储区实体会导致嵌套的结构切片切片错误

som*_*ne1 4 python google-app-engine go app-engine-ndb

出于性能原因,我正在Go的Google AppEngine项目中编写模块,但需要能够读取我在数据存储区中拥有的某些实体。我写了Go代码以能够读取我在Python中构建的实体,但出现以下错误:

datastore: flattening nested structs leads to a slice of slices: field "Messages"

Python中的模型定义:

class ModelB(ndb.Model):
    msg_id = ndb.StringProperty(indexed=False)
    cat_ids = ndb.StringProperty(repeated=True, indexed=False)
    list_ids = ndb.StringProperty(repeated=True, indexed=False)
    default_list_id_index = ndb.IntegerProperty(indexed=False)

class ModelA(ndb.Model):
    date_join = ndb.DateTimeProperty(auto_now_add=True)
    name = ndb.StringProperty()
    owner_salutation = ndb.StringProperty(indexed=False)
    owner_email_address = ndb.StringProperty()
    logo_url = ndb.StringProperty(indexed=False)
    ...
    messages = ndb.LocalStructuredProperty(ModelB, name='bm', repeated=True)
Run Code Online (Sandbox Code Playgroud)

在Go中:

type ModelB struct {
    MessageID          string   `datastore:"msg_id,noindex"`
    CategoryIDs        []string `datastore:"cat_ids,noindex"`
    ListIDs            []string `datastore:"list_ids,noindex"`
    DefaultListIDIndex int      `datastore:"default_list_id_index,noindex"`
}

type ModelA struct {
    DateJoin          time.Time `datastore:"date_join,"`
    Name              string    `datastore:"name,"`
    OwnerSalutation   string    `datastore:"owner_salutation,noindex"`
    OwnerEmailAddress string    `datastore:"owner_email_address,"`
    LogoURL           string    `datastore:"logo_url,noindex"`
    Messages          []ModelB  `datastore:"bm,"`
}
Run Code Online (Sandbox Code Playgroud)

我在这里做错什么了吗?Go与Python模型定义之间的功能仅仅是不兼容吗?

尝试解码ModelB

重新定义ModelA如下:

import pb "appengine_internal/datastore"
import proto "code.google.com/p/goprotobuf/proto"

type ModelA struct {
    DateJoin          time.Time `datastore:"date_join,"`
    Name              string    `datastore:"name,"`
    OwnerSalutation   string    `datastore:"owner_salutation,noindex"`
    OwnerEmailAddress string    `datastore:"owner_email_address,"`
    LogoURL           string    `datastore:"logo_url,noindex"`
    Messages          []ModelB  `datastore:"-"`
}

// Load is implemented for the PropertyLoaderSaver interface.

func (seller *ModelA) Load(c <-chan datastore.Property) error {
  f := make(chan datastore.Property, 100)
  for p := range c {
    if p.Name == "bm" {
      var val pb.EntityProto
      err := proto.Unmarshal([]byte(p.Value.(string)), &val)
      if err != nil {
        return err
      }
      //TODO: Store result as a new ModelB
    } else {
      f <- p
    }
  }
  close(f)
  return datastore.LoadStruct(seller, f)
}
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误: proto: required field "{Unknown}" not set

mji*_*son 5

Go数据存储区包不支持像这样的两层切片。您可以使用[]ModelB,只要ModelB不包含任何切片。或者,您可以ModelB在中使用ModelA,并且ModelB可以在其中包含切片。但你不能同时拥有[]ModelBModelB具有片。请参阅代码以了解错误情况。您的选择:

  1. 不要在Go中做
  2. 编写自己的数据存储解串器以处理这种情况-这可能很难
  3. 更改您的python数据结构以满足Go要求并重写您的数据

  • 还有其他的事情。在Python中,您不能具有包含重复子属性的重复StructuredProperty(这与Go约束相同)。在Python中无法使用它的原因是您使用了LocalStructuredProperty,它使用的编码与StructuredProperty的编码非常不同-它以字节字符串存储数据,其编码方式与顶级实体的编码方式相同。但是您的Go代码等同于使用StructuredProperty。也许您可以将其声明为字节字符串数组,然后分别解码它们?因为这就是Python中正在发生的事情。 (4认同)