(2020.8.12 追記)
本記事はGAE/Go 1st genの appengine/datastore
パッケージを使用した場合の内容となっています。
Client Library(cloud.google.com/go/datastore
パッケージ)を使用した場合はデフォルトの挙動が異なります。Client Libraryの場合構造体タグに flatten
を指定すると本記事と同様の挙動となります。
GAE/Go のDatastore APIはネストされた構造体を保存することが出来ます。
今回、構造体にsliceが絡んだ場合にどういうカタチで保存されるのかが興味あったので試してみました。
単一構造体ネスト
まずはシンプルに、構造体に構造体をネスト。
構造体定義
type Inner struct {
Name string
Value int
}
type Outer struct {
Name string
Inner Inner
}
保存
c := appengine.NewContext(r)
key := datastore.NewKey(c, "Outer", "test", 0, nil)
outer := Outer{
Name: "outer",
Inner: Inner{
Name: "inner",
Value: 999,
},
}
if _, err := datastore.Put(c, key, &outer); err != nil {
return err
}
結果
Inner.Name
Inner.Value
というdot区切りの別々のプロパティに展開されます。
構造体のslice
構造体のsliceをフィールドとして持つケース。
構造体定義
type Inner struct {
Name string
Value int
}
type Outer struct {
Name string
Inners []Inner
}
保存
key := datastore.NewKey(c, "Outer", "test", 0, nil)
outer := Outer{
Name: "outer",
Inners: []Inner{
Inner{
Name: "inner1",
Value: 111,
},
Inner{
Name: "inner1",
Value: 222,
},
},
}
if _, err := datastore.Put(c, key, &outer); err != nil {
return err
}
結果
Inners.Name
、 Inners.Value
それぞれがリストプロパティとして展開されました。(同じlengthになるということですね)
ネストされた構造体の中にslice
ネストされた構造体がsliceフィールドを持つケースです。
構造体定義
type Inner struct {
Names []string
Values []int
}
type Outer struct {
Name string
Inner Inner
}
保存
key := datastore.NewKey(c, "Outer", "test", 0, nil)
outer := Outer{
Name: "outer",
Inner: Inner{
Names: []string{"inner1-1", "inner1-2"},
Values: []int{11, 12, 13},
},
}
if _, err := datastore.Put(c, key, &outer); err != nil {
return err
}
結果
ネストされた構造体sliceのケースと同じ形式で展開されました。この場合だとlengthは同じとは限りません。
なるほどよく出来てる。
sliceの中にさらにslice
slice中構造体の中にさらにsliceがあった場合はどのように展開されるのでしょう?
構造体定義
type Inner struct {
Names []string
Values []int
}
type Outer struct {
Name string
Inners []Inner
}
保存
key := datastore.NewKey(c, "Outer", "test", 0, nil)
outer := Outer{
Name: "outer",
Inners: []Inner{
Inner{
Names: []string{"inner1-1", "inner1-2"},
Values: []int{11, 12},
},
Inner{
Names: []string{"inner2-1", "inner2-2"},
Values: []int{21, 22, 23},
},
},
}
if _, err := datastore.Put(c, key, &outer); err != nil {
return err
}
結果
datastore: flattening nested structs leads to a slice of slices: field "Inners"
というエラーになりました。
プロパティツリー中、異なる階層にsliceがあるとエラーになるのですね。
まとめ
あまり複雑なデータ構造に使用するのは厳しそうですが、プロパティをグルーピングするくらいに使うにはとても便利そう\(^o^)/
参考