質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

2305閲覧

golang gorm many2many 逆参照でのOR/AND検索を行いたい

minorm

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2021/03/26 11:39

編集2021/03/27 05:49

前提・実現したいこと

Many2Many 間で 逆参照を行い And/Or で検索結果を取得したい

2つのモデルがあります
※実現したいことに不要なFieldは全て取り除いています

go

1type Problem struct { 2 gorm.Model 3 Title string `json:"title" binding:"required"` 4 Tags []Tag `gorm:"many2many:problem_tags;"` 5} 6 7type Tag struct { 8 gorm.Model 9 Name string `json:"name" binding:"required"` 10 Problems []Problem `gorm:"many2many:problem_tags;"` 11}

Tag.Name が一つ / 複数与えられた時に
それらのTag.Nameを持つ Problemをすべて And/Or 検索して取得したいです

該当のソースコード

HTMLのForm から http://localhost:8080/?q=gin+gorm のようなクエリを飛ばして
c.Request.URL.Query() から query params を取得して
このparamsを用いて Problems を取得し表示

※paramsの取得は出来ています
※router.go, db.go などは省略します

go

1func Index(c *gin.Context) { 2 // ここで query parameters を取得 3 // params に入っているのは []string です 4 params, err := utils.URLQueryParse() 5 // err処理は省略 6 7 // !!ここ!! 8 output := []models.Problem{} 9 found := map[uint]bool{} 10 11 for _, tagname := range params { 12 var tag models.Tag 13 _ = tag.GetOneByName(tagname) 14 15 for _, p := range tag.Problems { 16 if _, ok := found[p.ID]; !ok { 17 output = append(output, p) 18 found[p.ID] = true 19 } 20 } 21 } 22 23 c.HTML(http.StatusOK, "Index.tmpl", gin.H{ 24 "Title": "Index", 25 "Result": params, 26 "Problems": output, 27 }) 28}

試したこと

上記のように無理やり実装はしました
一応動作はします

tag.GetOneByName は以下のようになっています

go

1// func (self *Tag)GetOneByName(tagName string) error 2// tagName に部分一致する、Tag.Nameを持つ最初の models.Tag(ID昇順で) レコードを取得する 3// 見つかったら nil, 一件も見つからなかったら "record not found" を吐く 4// Problems も全部取得する ので処理遅い はず 5func (self *Tag)GetOneByName(tagName string) error { 6 return db.DB.Preload("Problems").Where("name LIKE ?", "%"+tagName+"%").First(self).Error 7}

一応And検索も無理やり実装はしました
が、O(N^3) 位のアルゴリズムになっています

gorm.io の公式Referenceを見て Back-Refereceを発見したので
これは行けるだろうと思ってさんざん弄ったのですが、結局良くわかりませんでした

普通に考えると return db.DB.Model( ... ).Where( ... ).Association( ... ).Find( ... )
のような一行のSQLで取得出来ると思うのですが、可能でしょうか
生のSQLでの解消なども可能であればお願いします

補足情報(FW/ツールのバージョンなど)

bash

1❯ go version 2go version go1.16.2 linux/amd64 3 4❯ bat go go.mod 5go 1.16 6 7require ( 8 github.com/gin-gonic/gin v1.6.3 9 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 10 github.com/k0kubun/pp v3.0.1+incompatible 11 github.com/mattn/go-colorable v0.1.8 // indirect 12 golang.org/x/sys v0.0.0-20210324051608-47abb6519492 // indirect 13 gorm.io/driver/sqlite v1.1.4 14 gorm.io/gorm v1.21.3 15)

schemeは以下のとおりです

bash

1❯ sqlite3 test.db 2SQLite version 3.31.1 2020-01-27 19:55:54 3Enter ".help" for usage hints. 4 5sqlite> .tables 6problem_tags problems solves tags 7sqlite> 8sqlite> 9sqlite> .schema problems 10CREATE TABLE `problems` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`title` text,`statement` text,`answer` text,`url` text,PRIMARY KEY (`id`)); 11CREATE INDEX `idx_problems_deleted_at` ON `problems`(`deleted_at`); 12sqlite> 13sqlite> 14sqlite> .schema tags 15CREATE TABLE `tags` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,PRIMARY KEY (`id`)); 16CREATE INDEX `idx_tags_deleted_at` ON `tags`(`deleted_at`); 17sqlite> 18sqlite> 19sqlite> .schema problem_tags 20CREATE TABLE `problem_tags` (`tag_id` integer,`problem_id` integer,PRIMARY KEY (`tag_id`,`problem_id`),CONSTRAINT `fk_problem_tags_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`),CONSTRAINT `fk_problem_tags_problem` FOREIGN KEY (`problem_id`) REFERENCES `problems`(`id`));

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

普通に出来ました。。。

投稿2021/03/29 05:50

minorm

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問