LoginSignup
23
13

GAE/Go Datastore ネストされた構造体の保存(さらにsliceを組み合わせた場合)

Last updated at Posted at 2017-05-24

(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
	}

結果

スクリーンショット 2017-05-24 20.35.05.png

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
	}

結果

スクリーンショット 2017-05-24 20.41.51.png

Inners.NameInners.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
	}

結果

スクリーンショット 2017-05-24 20.55.47.png

ネストされた構造体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^)/

参考

23
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
13