将切片结构保存到Cloud Datastore(数据存储模式下的Firestore)的正确方法是什么?

时间:2019-08-20 15:36:32

标签: go google-cloud-firestore google-cloud-datastore

我想在Google Cloud Datastore(数据存储模式下的Firestore)中保存一部分结构。

以该电话簿和联系人为例。

type Contact struct {
  Key         *datastore.Key `json:"id" datastore:"__key__"`
  Email       string         `json:"email" datastore:",noindex"`
  Name        string         `json:"name" datastore:",noindex"`
}
type Phonebook struct {
  Contacts []Contact
  Title    string
}

保存并加载该结构没有问题,因为Datastore library会照顾它。

由于我的实际代码中存在一些复杂的属性,因此我需要实现PropertyLoadSaver方法。

保存Title属性非常简单。但是我在存储切片Contact结构时遇到问题。

我尝试使用SaveStruct方法:

func (pb *Phonebook) Save() ([]datastore.Property, error) {
  ps := []datastore.Property{
    {
      Name:    "Title",
      Value:   pb.Title,
      NoIndex: true,
    },
  }
  ctt, err := datastore.SaveStruct(pb.Contacts)
  if err != nil {
    return nil, err
  }
  ps = append(ps, datastore.Property{
    Name:    "Contacts",
    Value:   ctt,
    NoIndex: true,
  })

  return ps, nil
}

此代码可以编译,但是不起作用。

错误消息为datastore: invalid entity type

显式地制作Property切片也不起作用:

func (pb *Phonebook) Save() ([]datastore.Property, error) {
  ps := []datastore.Property{
    {
      Name:    "Title",
      Value:   pb.Title,
      NoIndex: true,
    },
  }
  cttProps := datastore.Property{
    Name:    "Contacts",
    NoIndex: true,
  }
  if len(pb.Contacts) > 0 {
    props := make([]interface{}, 0, len(pb.Contacts))
    for _, contact := range pb.Contacts {
      ctt, err := datastore.SaveStruct(contact)
      if err != nil {
        return nil, err
      }
      props = append(props, ctt)
    }
    cttProps.Value = props
  }
  ps = append(ps, cttProps)

  return ps, nil
}

制作实体切片也不起作用:

func (pb *Phonebook) Save() ([]datastore.Property, error) {
  ps := []datastore.Property{
    {
      Name:    "Title",
      Value:   pb.Title,
      NoIndex: true,
    },
  }
  cttProps := datastore.Property{
    Name:    "Contacts",
    NoIndex: true,
  }
  if len(pb.Contacts) > 0 {
    values := make([]datastore.Entity, len(pb.Contacts))
    props := make([]interface{}, 0, len(pb.Contacts))
    for _, contact := range pb.Contacts {
      ctt, err := datastore.SaveStruct(contact)
      if err != nil {
        return nil, err
      }
      values = append(values, datastore.Entity{
        Properties: ctt,
      })
    }
    for _, v := range values {
      props = append(props, v)
    }
    cttProps.Value = props
  }
  ps = append(ps, cttProps)

  return ps, nil
}

两者都产生了相同的错误datastore: invalid entity type

最后,我诉诸于使用JSON。联系人切片将转换为JSON数组。

func (pb *Phonebook) Save() ([]datastore.Property, error) {
  ps := []datastore.Property{
    {
      Name:    "Title",
      Value:   pb.Title,
      NoIndex: true,
    },
  }
  var values []byte
  if len(pb.Contacts) > 0 {
    js, err := json.Marshal(pb.Contacts)
    if err != nil {
      return nil, err
    }
    values = js
  }
  ps = append(ps, datastore.Property{
    Name:    "Contacts",
    Value:   values,
    NoIndex: true,
  })

  return ps, nil
}

除了使用JSON之外,还有其他更好的方法吗?

2 个答案:

答案 0 :(得分:0)

我发现了这个document,它提到src必须是一个结构指针。

答案 1 :(得分:0)

您似乎自定义保存电话簿的唯一原因似乎是避免在没有联系人的情况下保存“联系人”片。如果是这样,您只需按照以下方式定义PhoneBook,然后直接在PhoneBook对象上使用SaveStruct。

type Phonebook struct {
  Contacts []Contact `datastore:"Contacts,noindex,omitempty"`
  Title    string `datastore:"Title,noindex"`
}