- 投稿日:2020-10-23T22:02:53+09:00
Goで使えるファイルタイプ
Goでは、拡張子.goはGoのソースファイル。というふうにGoが認識するファイルタイプが決まっています。
また、テストを記述するファイルを作成するときに末尾につける_test.goもGoが認識するファイルの種類の一つとして、特別に扱われます。
拡張子.go
Goのソースファイルのこと
拡張子.c, .h
Cのソースファイルのこと
拡張子.cc, .cpp, .cxx, .hh, .hpp, .hxx
C++のソースファイルのこと
拡張子.m
Objective-Cのソースファイルのこと
拡張子.s, .S
アセンブラソースファイルのこと
拡張子.swig, .swigcxx
SWIGを定義するファイルのこと
拡張子.syso
システムオブジェクトのファイルのこと
最後に
これらは他のプログラミング言語との連携の際に使われるものです。それぞれGoで特別な役割があるということですね。いつどこで使うのかもこれから経験していきたいところです!
- 投稿日:2020-10-23T20:26:09+09:00
[Go] 画像の拡張子の変更をするCLIコマンドを作る
はじめに
このまえ、Gopher道場 の自習室とやらに参加させてもらい、前々から気になっていたGopher道場の課題をgithubにて探して、(やっていいのかな…?)演習しました。
その課題1ってのが画像の拡張子変更 でした。とりあえずアウトプットをしたいので、ここに色々書いていきます。また、使用したパッケージから、
flag
,os
,path/filepath
,image
について、ちょっとだけ解説していきます。環境
# go version go version go1.15.2 linux/amd64 # tree . |- conversion | |- conversion.go |- go.mod |- main.go実際のコード
とりあえず、リポジトリはここです
main.gopackage main import ( "cvs/conversion" "flag" "fmt" "os" "path/filepath" ) var ( extension string imagepath string dirpath string ) func main() { flag.StringVar(&extension, "e", "jpeg", "拡張子の指定") flag.StringVar(&imagepath, "f", "", "変換するファイルのパスの指定") flag.StringVar(&dirpath, "d", "", "変換後のファイル名の指定") flag.Parse() err := conversion.ExtensionCheck(extension) if err != nil { fmt.Println("Error:", err) os.Exit(1) } err = conversion.FilepathCheck(imagepath) if err != nil { fmt.Println("Error:", err) os.Exit(1) } err = conversion.DirpathCheck(dirpath) if err != nil { fmt.Println("Error:", err) os.Exit(1) } f := filepath.Ext(imagepath) err = conversion.FileExtCheck(f) if err != nil { fmt.Println("Error:", err) os.Exit(1) } fmt.Println("変換中・・・") err = conversion.FileExtension(extension, imagepath, dirpath) if err != nil { fmt.Println("Error:", err) os.Exit(1) } }conversion.go/* Conversion は 画像の拡張子の変更を行うためのパッケージです。 */ package conversion import ( "errors" "fmt" "image" "image/gif" "image/jpeg" "image/png" "os" _ "image/gif" _ "image/jpeg" _ "image/png" ) const ( JPEG = "jpeg" JPG = "jpg" GIF = "gif" PNG = "png" ) // -e で指定した拡張子が対応しているか、判断します。 func ExtensionCheck(ext string) error { switch ext { case JPEG, JPG, GIF, PNG: return nil default: return errors.New("指定できない拡張子です" + ext) } } // -f で指定したファイルが存在するか、判断します。 func FilepathCheck(imagepath string) error { switch imagepath { case "": return errors.New("ファイルの指定がされてません") default: if f, err := os.Stat(imagepath); os.IsNotExist(err) || f.IsDir() { return errors.New("ファイルが存在しません" + imagepath) } else { return nil } } } func DirpathCheck(dirpath string) error { switch dirpath { case "": return errors.New("変換後のファイル名が指定されていません") default: return nil } } func FileExtCheck(imagepath string) error { switch imagepath { case "." + JPEG, "." + JPG, "." + GIF, "." + PNG: return nil default: return errors.New("指定したファイルが対応していません。:" + imagepath) } } func FileExtension(extension string, imagepath string, dirpath string) error { exFile, err := os.Open(imagepath) defer exFile.Close() if err != nil { return errors.New("os.Create失敗") } output, err := os.Create(dirpath) defer output.Close() if err != nil { return errors.New("output失敗") } img, _, Err := image.Decode(exFile) if Err != nil { return errors.New("Decode失敗") } switch extension { case JPEG, JPG: err = jpeg.Encode(output, img, nil) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil case GIF: err = gif.Encode(output, img, nil) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil case PNG: err = png.Encode(output, img) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil } return nil }go.modmodule cvs go 1.15とりあえず、エラーハンドリングとかは適当にしつつ、ちゃんと動作するようにしました。
コード解説
今回のコードのテーマとして、
-go mod
を使う
-go doc
を使う
- パッケージを分けるというのを決めました。一応、理由としては、
1.go mod
により、パッケージの分割を使いやすくする
2.go doc
により、ドキュメントを作成することにより、可用性をあげる
この2つがあります。が、今回はパス。今回使用したパッケージについて、色々書いていきます。
画像の拡張子を変更するCLIコマンドのために使用したパッケージを上げると、
flag
os
path/filepath
image
があります。
それぞれ解説していきます。flag
ドキュメント
コマンドラインからオプションとして、引数を取得するときに使う実装したコード(main.go)var ( extension string imagepath string dirpath string ) func main() { flag.StringVar(&extension, "e", "jpeg", "拡張子の指定") // -e "文字列" で、文字列を取得する/デフォルトで"jpeg"が指定されている flag.StringVar(&imagepath, "f", "", "変換するファイルのパスの指定") flag.StringVar(&dirpath, "d", "", "変換後のファイル名の指定") flag.Parse() // Parseしないと、変数にパースされない ~~~省略書き方flag.StringVar(&変数名, "オプションの記号", "デフォルトの値","このオプションの説明")文字列の取得以外も取得はできる(はず)
os
ドキュメント
今回は、指定した画像が本当に存在するのか、画像を保存したりに使用しました。実装したコード(conversion.go)func FilepathCheck(imagepath string) error { switch imagepath { case "": return errors.New("ファイルの指定がされてません") default: if f, err := os.Stat(imagepath); os.IsNotExist(err) || f.IsDir() { return errors.New("ファイルが存在しません" + imagepath) } else { return nil } } } //-fで指定したファイルが存在するかを判定している関数ですこいつは結構なんでもできる。
path/filepath
ドキュメント
先程紹介した関数の引数の取得してます。stringからファイルパスを取得してます。実装したコード(main.go)f := filepath.Ext(imagepath) err = conversion.FileExtCheck(f) //imagepathが本当にあるのか、をチェックするimage
ドキュメント
画像処理系はこいつでできる。実装したコード(conversion.go)img, _, Err := image.Decode(exFile) if Err != nil { return errors.New("Decode失敗") } //画像をデコードする処理 switch extension { case JPEG, JPG: err = jpeg.Encode(output, img, nil) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil case GIF: err = gif.Encode(output, img, nil) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil case PNG: err = png.Encode(output, img) if err != nil { return errors.New("Encode失敗") } fmt.Println("変換成功") return nil } //変換後の拡張子に合わせてエンコードする画像処理はほぼこいつだけでできるっぽい
まとめ
実際に実行してみると、、、
# go build -o cvs # ./cvs -e png -f sample.jpeg -d sample.png 変換中・・・ 変換成功って感じで、変換できる。
ちなみに、-d のあとに.pngではなく、適当に書いても、拡張子としては、ちゃんと変換されています。
ブラウザで変換すると、へんなスクリプトを入れられるみたいなのもないし、安全。
やりごたえがあって、楽しかったから、またコマンド作ろうかしら。
では。
- 投稿日:2020-10-23T15:20:04+09:00
golang から Azure KeyVault を使ってデータを暗号/復号する
はじめに
以前 golang から Azure KeyValut を使用してデータを暗号化するのに、資料がなくて困ったので簡単にまとめました。
やってみよう
必用なもの
- Azureアカウント
- Azure KeyValut用プリンシパル
KeyVault暗号/復号用コード
まずは Azure 認証用のコードです。
NewAuthorizerFromEnvironment() での認証には以下の環境変数が必用です。
環境変数 説明 AZURE_TENANT_ID AzureのテナントID AZURE_CLIENT_ID AzureのクライアントID AZURE_CERTIFICATE_PATH 認証用証明書のパス AZURE_CERTIFICATE_PASSWORD 認証用証明書の復号パスワード azure.go (azure認証用コード)package auth import ( "log" ka "github.com/Azure/azure-sdk-for-go/services/keyvault/auth" "github.com/Azure/go-autorest/autorest" ) var ( AzureAuthorizer autorest.Authorizer ) func init() { var err error AzureAuthorizer, err = ka.NewAuthorizerFromEnvironment() if err != nil { log.Fatal(err) } }次に暗号/復号処理の実装です。
といっても、Azure が用意したメソッドを実行するだけです。
以下の環境変数が必用です。
環境変数 説明 AZURE_VAULT_BASE_URL Azure KeyVault のベースURL(xxx.vault.azure.net) AZURE_VAULT_GENERAL_KEY_NAME 鍵名未指定の暗号に使用するデフォルト鍵名 key.go 暗号/復号処理package vault import ( "context" "log" "os" kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault" "./auth" ) var ( VaultBaseURL string GeneralKeyName string ) func init() { VaultBaseURL = os.Getenv("AZURE_VAULT_BASE_URL") if len(VaultBaseURL) == 0 { log.Fatal("Please set environment variable \"AZURE_VAULT_BASE_URL\"") } GeneralKeyName = os.Getenv("AZURE_VAULT_GENERAL_KEY_NAME") if len(GeneralKeyName) == 0 { log.Fatal("Please set environment variable \"AZURE_VAULT_GENERAL_KEY_NAME\"") } } // keyVersion = "" -> use current key version func Encrypt(keyName string, keyVersion string, plain *string) (kv.KeyOperationResult, error) { params := kv.KeyOperationsParameters{ Algorithm: kv.RSAOAEP256, Value: plain, } c := kv.New() c.Authorizer = auth.AzureAuthorizer return c.Encrypt(context.Background(), VaultBaseURL, keyName, keyVersion, params) } // keyVersion = "" -> use current key version func GeneralEncrypt(plain *string) (kv.KeyOperationResult, error) { return Encrypt(GeneralKeyName, "", plain) } // keyVersion = "" -> use current key version func Decrypt(keyName string, keyVersion string, encrypted *string) (kv.KeyOperationResult, error) { params := kv.KeyOperationsParameters{ Algorithm: kv.RSAOAEP256, Value: encrypted, } c := kv.New() c.Authorizer = auth.AzureAuthorizer return c.Decrypt(context.Background(), VaultBaseURL, keyName, keyVersion, params) } // keyVersion = "" -> use current key version func GeneralDecrypt(keyVersion string, encrypted *string) (kv.KeyOperationResult, error) { return Decrypt(GeneralKeyName, keyVersion, encrypted) }実行例
main.goplain := hex.EncodeToString([]byte("plain text")) enc, _ := vault.GeneralEncrypt(&plain) encrypted := *enc.Result keyName := vault.GeneralKeyName keyVersion := path.Base(*enc.Kid) dec, _ := vault.Decrypt(keyName, keyVersion, &encrypted) str, _ := hex.DecodeString(*dec.Result)
- 投稿日:2020-10-23T02:43:15+09:00
Dataloadersを使ったN+1問題への対応
お題
Golang製GraphQLライブラリであるgqlgenの「Dataloaders」を使って、N+1問題(ググるとわんさか記事が出てくる)を解決する。
想定する読者
- Golangについてある程度書ける。
- 「GraphQL is 何?」ではない。
- gqlgenの getting-started で初期セットアップくらいはやったことがある。
関連記事索引
- 第11回「Dataloadersを使ったN+1問題への対応」
- 第10回「GraphQL(gqlgen)エラーハンドリング」
- 第9回「GraphQLにおける認証認可事例(Auth0 RBAC仕立て)」
- 第8回「GraphQL/Nuxt.js(TypeScript/Vuetify/Apollo)/Golang(gqlgen)/Google Cloud Storageの組み合わせで動画ファイルアップロード実装例」
- 第7回「GraphQLにおけるRelayスタイルによるページング実装(後編:フロントエンド)」
- 第6回「GraphQLにおけるRelayスタイルによるページング実装(前編:バックエンド)」
- 第5回「DB接続付きGraphQLサーバ(by Golang)をローカルマシン上でDockerコンテナ起動」
- 第4回「graphql-codegenでフロントエンドをGraphQLスキーマファースト」
- 第3回「go+gqlgenでGraphQLサーバを作る(GORM使ってDB接続)」
- 第2回「NuxtJS(with Apollo)のTypeScript対応」
- 第1回「frontendに「nuxtjs/apollo」、backendに「go+gqlgen」の組み合わせでGraphQLサービスを作る」
開発環境
# OS - Linux(Ubuntu)
$ cat /etc/os-release NAME="Ubuntu" VERSION="18.04.5 LTS (Bionic Beaver)"# バックエンド
# 言語 - Golang
$ go version go version go1.15.2 linux/amd64# gqlgen
v0.13.0IDE - Goland
GoLand 2020.2.3 Build #GO-202.7319.61, built on September 16, 2020今回の全ソース
Dataloaders導入前
https://github.com/sky0621/study-gqlgen/tree/v0.4/dataloaders
Dataloaders導入後
https://github.com/sky0621/study-gqlgen/tree/v0.5/dataloaders
実践
Dataloaders導入前
GraphQLスキーマ
例えば以下のようなGraphQLスキーマがあったとして、
schema.graphqlstype User { id: ID! name: String! todos: [Todo] } type Todo { id: ID! task: String! user: User! } type Query { users: [User!]! todos: [Todo!]! }type
Todo
が持つuser
、及び、typeUser
が持つtodos
には専用のリゾルバーを用意するものとする。
(今後、1件ないし条件に合致するtodo
やuser
を取得するクエリを用意する時にもロジックが流用できるため。)モデル
user.gotype User struct { ID int64 `json:"id"` Name string `json:"name"` }todo.gotype Todo struct { ID int64 `json:"id"` Task string `json:"task"` UserID int64 `json:"user_id" db:"user_id"` }データベース
1人のユーザーが2件ずつToDoを持っている状態
user
テーブル
todo
テーブルメイン動線
とりあえず、DBハンドラーの生成とGraphQLサーバの起動。
DBはSQLiteを使っておく。main.go(import文は省略)func main() { http.Handle("/", playground.Handler("GraphQL playground", "/query")) http.Handle("/query", handler.NewDefaultServer( generated.NewExecutableSchema( generated.Config{ Resolvers: &graph.Resolver{ DB: sqlx.MustOpen("sqlite3", "./data.db"), }, }, ), )) log.Fatal(http.ListenAndServe(":8080", nil)) }リゾルバー
schema.resolvers.gopackage graph import ( "context" "errors" "fmt" "log" "github.com/sky0621/study-gqlgen/dataloaders/graph/generated" "github.com/sky0621/study-gqlgen/dataloaders/graph/model" ) // users: [User!]! に対応 func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) { 〜〜 後ほど解説 〜〜 } // todos: [Todo!]! に対応 func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) { 〜〜 後ほど解説 〜〜 } // type User の todos: [Todo] 取得用 func (r *userResolver) Todos(ctx context.Context, obj *model.User) ([]*model.Todo, error) { 〜〜 後ほど解説 〜〜 } // type Todo の user: User! 取得用 func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) { 〜〜 後ほど解説 〜〜 } // Query returns generated.QueryResolver implementation. func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } // User returns generated.UserResolver implementation. func (r *Resolver) User() generated.UserResolver { return &userResolver{r} } // Todo returns generated.TodoResolver implementation. func (r *Resolver) Todo() generated.TodoResolver { return &todoResolver{r} } type queryResolver struct{ *Resolver } type userResolver struct{ *Resolver } type todoResolver struct{ *Resolver }users: [User!]!
単純に全ユーザーを取得するだけ。
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) { var users []*model.User sql := "SELECT * FROM user" log.Print(sql) if err := r.DB.SelectContext(ctx, &users, sql); err != nil { log.Print(err) return nil, err } return users, nil }todos: [Todo!]!
単純に全ToDoを取得するだけ。
func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) { var todos []*model.Todo sql := "SELECT * FROM todo" log.Print(sql) if err := r.DB.SelectContext(ctx, &todos, sql); err != nil { log.Print(err) return nil, err } return todos, nil }type User の todos: [Todo]
1ユーザーの情報取得時に追加で実行されるクエリ。
1ユーザー毎に追加で実行されるので、つまり、5ユーザーの情報取得時には、+5回SQLが発行される計算。func (r *userResolver) Todos(ctx context.Context, obj *model.User) ([]*model.Todo, error) { if obj == nil { return []*model.Todo{}, nil } var todos []*model.Todo sql := fmt.Sprintf("SELECT * FROM todo WHERE user_id = %d", obj.ID) log.Print(sql) if err := r.DB.SelectContext(ctx, &todos, sql); err != nil { log.Print(err) return nil, err } return todos, nil }type Todo の user: User!
1ToDoの情報取得時に追加で実行されるクエリ。
1ToDo毎に追加で実行されるので、つまり、4ToDoの情報取得時には、+4回SQLが発行される計算。func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) { if obj == nil { return nil, nil } var users []*model.User sql := fmt.Sprintf("SELECT * FROM user WHERE id = %d", obj.UserID) log.Print(sql) if err := r.DB.SelectContext(ctx, &users, sql); err != nil { log.Print(err) return nil, err } if len(users) != 1 { log.Print("users length is not 1") return nil, errors.New("err") } return users[0], nil }動作確認
GraphQLでの
users
クエリとtodos
クエリの実行パターン毎に結果とクエリ発行回数を表示1)
users
(todos
リクエストなし)クエリと結果(playground表記)
SQL発行ログ
2020/10/22 00:07:01 SELECT * FROM user2)
users
(todos
リクエストあり)クエリと結果
query users { users { id name todos { id task } } }
結果
{ "data": { "users": [ { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] }, { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] }, { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] }, { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] }, { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } ] } }SQL発行ログ
2020/10/22 00:08:33 SELECT * FROM user 2020/10/22 00:08:33 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:08:33 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:08:33 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:08:33 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:08:33 SELECT * FROM todo WHERE user_id = 4全ユーザー取得後、ユーザー1人ずつ、ToDoを取得するSQLが発行されている。
結果、計6回のSQL発行となっている。3)
todos
(users
リクエストなし)クエリと結果
query todos { todos { id task } }
結果
{ "data": { "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" }, { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" }, { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" }, { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" }, { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }SQL発行ログ
2020/10/22 00:21:25 SELECT * FROM todo4)
todos
(users
リクエストあり)クエリと結果
query todos { todos { id task user { id name } } }
結果
{ "data": { "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato" } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato" } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato" } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato" } }, { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki" } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki" } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki" } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki" } }, { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi" } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi" } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi" } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi" } }, { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka" } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka" } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka" } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka" } }, { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito" } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito" } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito" } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito" } } ] } }SQL発行ログ
2020/10/22 00:24:44 SELECT * FROM todo 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5全ToDo取得後、ToDo1件ずつ、ユーザーを取得するSQLが発行されている。
結果、計21回のSQL発行となっている。5)より複雑な例
今回のGraphQLスキーマでは
ToDo
とUser
が互いを参照し合う循環参照構造にしている。
そのため、やろうと思えば以下のようなクエリを流すこともできる。クエリと結果
query todos { todos { id task user { id name todos { id task user { id name todos { id task user { id name todos { id task } } } } } } } }
結果
{ "data": { "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 2, "task": "やること 2", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 3, "task": "やること 3", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } }, { "id": 4, "task": "やること 4", "user": { "id": 1, "name": "Sato", "todos": [ { "id": 1, "task": "やること 1" }, { "id": 2, "task": "やること 2" }, { "id": 3, "task": "やること 3" }, { "id": 4, "task": "やること 4" } ] } } ] } } ] } }, { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 6, "task": "やること 6", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 7, "task": "やること 7", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } }, { "id": 8, "task": "やること 8", "user": { "id": 2, "name": "Suzuki", "todos": [ { "id": 5, "task": "やること 5" }, { "id": 6, "task": "やること 6" }, { "id": 7, "task": "やること 7" }, { "id": 8, "task": "やること 8" } ] } } ] } } ] } }, { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 10, "task": "やること10", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 11, "task": "やること11", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } }, { "id": 12, "task": "やること12", "user": { "id": 3, "name": "Takahashi", "todos": [ { "id": 9, "task": "やること 9" }, { "id": 10, "task": "やること10" }, { "id": 11, "task": "やること11" }, { "id": 12, "task": "やること12" } ] } } ] } } ] } }, { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 14, "task": "やること14", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 15, "task": "やること15", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } }, { "id": 16, "task": "やること16", "user": { "id": 4, "name": "Tanaka", "todos": [ { "id": 13, "task": "やること13" }, { "id": 14, "task": "やること14" }, { "id": 15, "task": "やること15" }, { "id": 16, "task": "やること16" } ] } } ] } } ] } }, { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 18, "task": "やること18", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 19, "task": "やること19", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } }, { "id": 20, "task": "やること20", "user": { "id": 5, "name": "Ito", "todos": [ { "id": 17, "task": "やること17" }, { "id": 18, "task": "やること18" }, { "id": 19, "task": "やること19" }, { "id": 20, "task": "やること20" } ] } } ] } } ] } } ] } }SQL発行ログ
計841回のSQL発行ログ
2020/10/22 00:34:57 SELECT * FROM todo 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 2 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 1 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM user WHERE id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 5 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 3 2020/10/22 00:34:57 SELECT * FROM todo WHERE user_id = 4考察
というように、何も考えず自由気ままにスキーマ定義して、汎用性を考慮してシンプルなSQL発行になるようにすると、結果、膨大な回数のSQL発行を行うことになる。
最後の循環参照構造についてはクライアントを一般公開している場合、何の制限もかけていないとフランクにDOSアタックを受けることになるのだけど、その対策については後述。
まずは、SQL発行回数を減らす方策を検討する。
単純に考えれば、リゾルバー毎にチューニングしたSQLを用意すればいいだけ。
つまり、
type User の todos: [Todo]
用のリゾルバーや
type Todo の user: User!
用のリゾルバーを用意せず、
(r *queryResolver) Users(ctx context.Context) ([]*model.User, error)
(r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error)
の中でリクエストに積まれた内容に応じたSQLを都度つど生成すればいいということ。
ただし、
そのような方策をとると、至極柔軟なGraphQLクエリのリクエストに対応するために、複雑なSQL生成ロジックを用意する羽目になる。
できればSQLはシンプルに抑えたい。
ということで登場するのがDataloaders。Dataloaders導入後
導入手順
基本的に以下に沿ってソースを自動生成。
https://gqlgen.com/reference/dataloaders/#dataloaderまあ、↑に書いてあるのだけど、
go get github.com/vektah/dataloadenで
dataloaden
を取得し、ソースを自動生成したいパス(例えば今回は、study-gqlgen/dataloaders/graph/
)で、go run github.com/vektah/dataloaden UserLoader int *github.com/sky0621/study-gqlgen/dataloaders/graph/model.Userと
go run github.com/vektah/dataloaden TodoLoader int64 []*github.com/sky0621/study-gqlgen/dataloaders/graph/model.Todoとする。真ん中あたりにある
int
は、user
やtodo
をユニークに特定するキーとなる要素の型。
今回だと、user
テーブルもtodo
テーブルもPKをinteger
にしているので、int
にしておく。
PKがUUIDみたいに文字列だったりするのなら、
go run github.com/vektah/dataloaden UserLoader string *github.com/sky0621/study-gqlgen/dataloaders/graph/model.Userにすればいい。
また、生成する型に関して、
model.User
は、ただのポインタで、model.Todo
はスライスにしている。
これは、それぞれの使われ方が以下のように異なるため。
model.User
todos
リゾルバーにより複数のtodo
が取得されたあと、1ToDo毎に紐づくユーザーを取得するリゾルバー((r *todoResolver) User(~~)
)が呼ばれるが、そこで使われる。
そこでは、1ToDoに紐づく1ユーザーが取れればいいので、ただのポインタで返すdataloaderを用意。
model.Todo
users
リゾルバーにより複数のuser
が取得されたあと、1ユーザー毎に紐づくToDoを取得するリゾルバー((r *userResolver) Todos(~~)
)が呼ばれるが、そこで使われる。
そこでは、1ユーザーに紐づく複数のToDoが取得されるので、スライスで返すdataloaderを用意。自動生成ソース(解説なし)
上記
dataloaden
コマンドで自動生成したソースは下記。userloader_gen.go
// Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package graph import ( "sync" "time" "github.com/sky0621/study-gqlgen/dataloaders/graph/model" ) // UserLoaderConfig captures the config to create a new UserLoader type UserLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []int) ([]*model.User, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewUserLoader creates a new UserLoader given a fetch, wait, and maxBatch func NewUserLoader(config UserLoaderConfig) *UserLoader { return &UserLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // UserLoader batches and caches requests type UserLoader struct { // this method provides the data for the loader fetch func(keys []int) ([]*model.User, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[int]*model.User // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *userLoaderBatch // mutex to prevent races mu sync.Mutex } type userLoaderBatch struct { keys []int data []*model.User error []error closing bool done chan struct{} } // Load a User by key, batching and caching will be applied automatically func (l *UserLoader) Load(key int) (*model.User, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a User. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *UserLoader) LoadThunk(key int) func() (*model.User, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*model.User, error) { return it, nil } } if l.batch == nil { l.batch = &userLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*model.User, error) { <-batch.done var data *model.User if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *UserLoader) LoadAll(keys []int) ([]*model.User, []error) { results := make([]func() (*model.User, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } users := make([]*model.User, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { users[i], errors[i] = thunk() } return users, errors } // LoadAllThunk returns a function that when called will block waiting for a Users. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *UserLoader) LoadAllThunk(keys []int) func() ([]*model.User, []error) { results := make([]func() (*model.User, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*model.User, []error) { users := make([]*model.User, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { users[i], errors[i] = thunk() } return users, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *UserLoader) Prime(key int, value *model.User) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *UserLoader) Clear(key int) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *UserLoader) unsafeSet(key int, value *model.User) { if l.cache == nil { l.cache = map[int]*model.User{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *userLoaderBatch) keyIndex(l *UserLoader, key int) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *userLoaderBatch) startTimer(l *UserLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *userLoaderBatch) end(l *UserLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) }todoloader_gen.go
// Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package graph import ( "sync" "time" "github.com/sky0621/study-gqlgen/dataloaders/graph/model" ) // TodoLoaderConfig captures the config to create a new TodoLoader type TodoLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []int64) ([][]*model.Todo, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewTodoLoader creates a new TodoLoader given a fetch, wait, and maxBatch func NewTodoLoader(config TodoLoaderConfig) *TodoLoader { return &TodoLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // TodoLoader batches and caches requests type TodoLoader struct { // this method provides the data for the loader fetch func(keys []int64) ([][]*model.Todo, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[int64][]*model.Todo // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *todoLoaderBatch // mutex to prevent races mu sync.Mutex } type todoLoaderBatch struct { keys []int64 data [][]*model.Todo error []error closing bool done chan struct{} } // Load a Todo by key, batching and caching will be applied automatically func (l *TodoLoader) Load(key int64) ([]*model.Todo, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Todo. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TodoLoader) LoadThunk(key int64) func() ([]*model.Todo, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]*model.Todo, error) { return it, nil } } if l.batch == nil { l.batch = &todoLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]*model.Todo, error) { <-batch.done var data []*model.Todo if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *TodoLoader) LoadAll(keys []int64) ([][]*model.Todo, []error) { results := make([]func() ([]*model.Todo, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } todos := make([][]*model.Todo, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { todos[i], errors[i] = thunk() } return todos, errors } // LoadAllThunk returns a function that when called will block waiting for a Todos. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TodoLoader) LoadAllThunk(keys []int64) func() ([][]*model.Todo, []error) { results := make([]func() ([]*model.Todo, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]*model.Todo, []error) { todos := make([][]*model.Todo, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { todos[i], errors[i] = thunk() } return todos, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *TodoLoader) Prime(key int64, value []*model.Todo) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]*model.Todo, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *TodoLoader) Clear(key int64) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *TodoLoader) unsafeSet(key int64, value []*model.Todo) { if l.cache == nil { l.cache = map[int64][]*model.Todo{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *todoLoaderBatch) keyIndex(l *TodoLoader, key int64) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *todoLoaderBatch) startTimer(l *TodoLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *todoLoaderBatch) end(l *TodoLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) }使い方
理屈としては、下記。
例えば、ユーザー情報を含む全ToDoを取得する時、1リクエストにつき以下のSQL発行をしていた。2020/10/22 00:24:44 SELECT * FROM todo 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 1 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 2 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 3 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 4 2020/10/22 00:24:44 SELECT * FROM user WHERE id = 5それに対して、dataloaderでは、1リクエストを受けて各種リゾルバーが発火している間、一定時間(ないし一定数の検索用 ID が溜まるまで)待機する。
それにより、今までWHERE id = 1
等としていて複数回SQLを発行しないといけなかったものを、WHERE id IN (1, 2, 3, ..)
として1回(件数次第では2〜N回)に減らすようにする。上記を実現するために、HTTPリクエストスコープをフックするミドルウェアを定義し、その中で自動生成したソースの機能を使いながら、id おまとめタイプのSQL文を発行する。
HTTPリクエストスコープをフックするミドルウェア
server.go(package,import文は省略)func main() { db := sqlx.MustOpen("sqlite3", "./data.db") http.Handle("/", playground.Handler("GraphQL playground", "/query")) http.Handle("/query", graph.Middleware( <-- 追加! db, handler.NewDefaultServer( generated.NewExecutableSchema( generated.Config{ Resolvers: &graph.Resolver{ DB: db, }, }, ), )), ) log.Fatal(http.ListenAndServe(":8080", nil)) }
graph.Middleware(~~)
でハンドラーをラップ。ミドルウェア
書きっぷりは以下に記載のソースをトレースしているので細かい説明は無し。
https://gqlgen.com/reference/dataloaders/#dataloaderこれにより、最大1ミリ秒の待機、ないし、最大 100 個分の id が溜まったタイミングで、
UserLoader
、TodoLoader
内の fetch 関数で定義したSQL発行が呼び出せるようになる。graph/dataloaders.gopackage graph import ( "context" "log" "net/http" "strconv" "strings" "time" "github.com/jmoiron/sqlx" "github.com/sky0621/study-gqlgen/dataloaders/graph/model" ) const loadersKey = "dataLoaders" type Loaders struct { UsersByIDs UserLoader TodosByUserIDs TodoLoader } func Middleware(conn *sqlx.DB, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), loadersKey, &Loaders{ UsersByIDs: UserLoader{ maxBatch: 100, wait: 1 * time.Millisecond, // 最大1ミリ秒待機した結果、ないし、最大 100 個のGraphQLクエリが溜まった分の id のスライスが ids という名前で渡ってくる。 fetch: func(ids []int64) ([]*model.User, []error) { if len(ids) == 0 { return nil, nil } sql := "SELECT * FROM user WHERE id IN (" + toPKs(ids) + ")" log.Print(sql) var users []*model.User if err := conn.SelectContext(r.Context(), &users, sql); err != nil { log.Print(err) return nil, []error{err} } // ids の中の id 毎にデータをマッピングする必要がある。 userById := map[int64]*model.User{} for _, user := range users { userById[user.ID] = user } results := make([]*model.User, len(ids)) for i, id := range ids { results[i] = userById[id] } return results, nil }, }, TodosByUserIDs: TodoLoader{ maxBatch: 100, wait: 1 * time.Millisecond, // 最大1ミリ秒待機した結果、ないし、最大 100 個のGraphQLクエリが溜まった分の id のスライスが ids という名前で渡ってくる。 fetch: func(userIDs []int64) ([][]*model.Todo, []error) { if len(userIDs) == 0 { return nil, nil } sql := "SELECT * FROM todo WHERE user_id IN (" + toPKs(userIDs) + ")" log.Print(sql) var todos []*model.Todo if err := conn.SelectContext(r.Context(), &todos, sql); err != nil { log.Print(err) return nil, []error{err} } // ids の中の id 毎にデータをマッピングする必要がある。 todoByUserId := map[int64][]*model.Todo{} for _, todo := range todos { todoByUserId[todo.UserID] = append(todoByUserId[todo.UserID], todo) } results := make([][]*model.Todo, len(userIDs)) for i, id := range userIDs { results[i] = todoByUserId[id] } return results, nil }, }, }) r = r.WithContext(ctx) next.ServeHTTP(w, r) }) } func For(ctx context.Context) *Loaders { return ctx.Value(loadersKey).(*Loaders) } func toPKs(ids []int64) string { // ids をSQL文の IN 句に指定できる形に変換 var pks []string for _, id := range ids { pks = append(pks, strconv.FormatInt(id, 10)) } return strings.Join(pks, ",") }リゾルバー
dataloader使用前は以下の各関数内に1ユーザー毎のToDo取得用SQL発行、1ToDo毎のユーザー取得用SQL発行を書いていたが、dataloader側にロジックを寄せたので、リゾルバー内は以下の通り簡素になる。
graph/schema.resolvers.go(dataloader使用前と変わった部分だけ抜粋)func (r *userResolver) Todos(ctx context.Context, obj *model.User) ([]*model.Todo, error) { if obj == nil { return []*model.Todo{}, nil } return For(ctx).TodosByUserIDs.Load(obj.ID) } func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) { if obj == nil { return nil, nil } return For(ctx).UsersByIDs.Load(obj.UserID) }動作確認
クエリと結果はdataloader使用前と同じなので、SQL発行結果だけ。
これなら、ToDoの件数やユーザー数がいくら増えても、その分だけSQL発行回数が増えるということはない。■
users
(todos
リクエストあり)2020/10/23 02:33:03 SELECT * FROM user 2020/10/23 02:33:03 SELECT * FROM todo WHERE user_id IN (5,1,3,4,2)■
todos
(users
リクエストあり)2020/10/23 02:33:59 SELECT * FROM todo 2020/10/23 02:33:59 SELECT * FROM user WHERE id IN (5,1,2,3,4)まとめ
そもそも紐づく情報や子階層の情報を取得するのに親情報の1件1件毎にSQL発行すること自体、ありえないけど、こうしたN+1問題と言われるものは大昔からあるみたい。
大抵は使用する言語でよく使うフレームワークあたりが解決手段をライブラリとして提供してたりするので、あまり意識することはないかもしれないけど。ちなみに、Dataloaderによる自動生成は、慣れてしまうと、どうということはないのだろうけど、(重要な部分は自動生成とは言え)キーの型をどうするかや関数の戻り値はポインタにするのかスライスにするのか等、どう使われるかを考慮の上、決めなくてはいけないので、最初はけっこう迷いは生じる。
スキーマ構造が循環参照していることにより、いくらでも複雑なクエリが叩けてしまう件については、力尽きたので、また次の機会に。