🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

3回答

2643閲覧

Laravelでリレーション関係が深いデータを取得するコードのアドバイス(コードレビュー)をして頂きたいです。

howaito

総合スコア9

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

1グッド

5クリップ

投稿2021/02/02 09:28

編集2021/02/03 01:42

解決したいこと(というよりアドバイス頂きたいこと)

現在、Laravel6で小説の投稿サイトを作成しています。

そこで、リレーション関係の深いデータを取得する場面に出会しました。

一応やりたいことはできたのですが、何だかもっと良いコードの書き方があるような気がします。

そのため、自分のコードが綺麗かどうなのか。もっと他によいコードの書き方があるのか。あるいは中間テーブルを作った方が良いのか、などをアドバイスして頂きたく投稿させていただきました。

##やりたいこと
やりたいことはとてもシンプルでして、『あるユーザーがコメントされたレコードを全て取得したい』です。
(あるユーザーがコメントしたレコードではありません。)

##【追記】
やりたいことが説明不足だったため追記します。
下記画像のように、ユーザー(作家)のプロフィールからコメントされた一覧を表示しようと考えています。
イメージ説明

テーブル設計

テーブル設計は以下の通りです。

イメージ説明

【補足】
users テーブル・・・ユーザー情報の管理
novelsテーブル・・・小説情報の管理
episodesテーブル・・・エピソード情報の管理(小説の中にエピソードが沢山ある)
commentsテーブル・・・コメント情報の管理(エピソードの中にコメントが沢山ある)

commentsテーブルuser_idにはコメントをしたユーザーのIDを保存しています。

自分で書いたコード

テーブル設計が上記の通りなので、コメントされたデータを取得しようとすると、usersテーブル→novelsテーブル→episodesテーブル→commentsテーブルというように、関係が深くなってしまいます。

下記のコードでひとまず、自分が取得したいデータは全て取得することができました。

php

1$novels_id = User::find($user_id)->novels()->pluck('id'); 2$episodes_id = Episode::whereIn('novel_id', $novels_id)->pluck('id'); 3$comments = Comment::with('episode.novel', 'user')->whereIn('episode_id', $episodes_id)->get();

しかし、あまり綺麗なコードでもないと思うので、もっと他に良い書き方などがありましたら、アドバイス頂きたいです。

##他に考えた方法
他に考えた方法としては

Commentsテーブルnovel_idカラム(FK)writer_idカラム(FK)などを追加する
・中間テーブルを作る。

などは考えたのですが、それなら上記のコードのままでも良いかなぁ、、、と思いました。

お手数をおかけしますが、アドバイスなど頂けましたら大変助かります。

何卒よろしくお願い致しますm(_ _)m

hoshi-takanori👍を押しています

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

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

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

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

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

guest

回答3

0

DBの取得に関するロジックが肥大化してしまう要因としては,

  1. 保存形式が悪い つまりDB構造が原因の場合
  2. 取得のクエリに無駄がある

などが挙げられると思います。もっとシンプルなコードにできるか考える際は1,2の順番で考えていくといいでしょう。

まず前者の視点(1)では,既存の回答でもあるように今のDB構造で問題ないと思います。

では,後者の(2)を見てみるとどうやら無駄な記載がある様にも思えますし,Laravelのリレーションに関する便利な機能(Eloquent ORM)を活用できていない様にも見えます。

やりたいことはとてもシンプルでして、『あるユーザーがコメントされたレコードを全て取得したい』です。

(あるユーザーがコメントしたレコードではありません。)

自分の投稿した小説のエピソードにコメントがあった際はそれを取得するという認識でよろしかったでしょうか?その場合は以下で取得できます。

PHP

1 2// App\Models\User.php 3 4 public function hasComments() 5 { 6 return $this->hasMany(Novel::class) 7 ->has('episodes.comments') 8 ->with(['episodes.comments', 'user']) 9 ->get(); 10 }

PHP

1// Controller 2 3 public function __invoke() 4 { 5 $user_id = 1; // 検証用 6 $hoge = User::find($user_id)->hasComments(); 7 dd($hoge->toArray()); // 検証用 8 } 9

イメージ説明

投稿2021/02/02 18:50

kai0310

総合スコア2076

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

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

howaito

2021/02/03 01:46

kaiさん、ご回答ありがとうございますm(_ _)m やりたいことが説明不足だったため、勘違いさせてしまい申し訳ございません。 今回やりたかったことは、既に追記した通り、コメントされた一覧を表示する。というものでした(汗) ただ、回答して頂いたようにモデル側でwithメソッドを使う方法はあまり利用していなかったので、この機会に今後は活用させていただこうと思います!ありがとうございますm(_ _)m
kai0310

2021/02/03 06:50

やりたいことについての追記を確認しましたが、まだ何をしたいかが分からないという状況です。 ユーザー(作家)のプロフィールからコメントされた一覧とありますがあるユーザとどういう関係があるのですか? - あるユーザがコメントしたものなのか - あるユーザが投稿したエピソードについたコメントなのか などもっと具体的に教えてください。第三者に自分の考えていることを伝えるということは大切なことです。
howaito

2021/02/03 09:19 編集

度々申し訳ありません。 コメントしていただいた後者(あるユーザが投稿したエピソードについたコメント)が今回実現したいことです! そのため、回答して頂いた方法ですと、下記のよう(正確にはオブジェクトの有無で分岐も必要?)になると思いました。 ``` foreach ($novels as $novel) { foreach ($novel->episodes as $episode) { foreach ($episode->comments as $comment) { dd($comment); } } } ``` 個人的にforeachを二重にするとわかりにくいかな?と考えています。 そのため、自分でもforeachを二重にする方法での実装方法は考えついたのですが、現在は質問時に投稿したコードを利用しています。 >第三者に自分の考えていることを伝えるということは大切なことです。 おっしゃる通りだと思います。ご指摘ありがとうございますm(_ _)m
guest

0

リレーションは複雑なのでドキュメントをよく読まないと難しいけど。
Has Many Throughでuserから直接episodeを取得できる。
https://readouble.com/laravel/6.x/ja/eloquent-relationships.html#has-many-through

User

public function episodes() { return $this->hasManyThrough(Episode::class, Novel::class); }
$user->episodes();
$user->episodes()->comments;

投稿2021/02/03 02:33

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

howaito

2021/02/03 09:21

この度は回答頂きありがとうございますm(_ _)m アドバイス頂いた方法ですと、「$user->episodes()->comments;」こちらはエラーが発生しました。 下記のようにするとcommentを取得することができると思うのですが、間違い無いでしょうか? ``` foreach ($user->episodes(); as $episode) { foreach ($episode->comments as $comment) { dd($comment); } } ``` ただ、個人的にforeachを二重にするとわかりにくいかな?と考えています。 そのため、自分でもforeachを二重にする方法での実装方法は考えついたのですが、現在は質問時に投稿したコードを利用しています。
guest

0

関係が深くなってしまいます。

適切に正規化した結果テーブルが増えすぎたなら正規化のレベルを浅くしましょう
だけどテーブル見た感じそのままで良いと思います
個人的な意見ですが、正規化はどんなシステムでも適している事が多いであって必ず最適という訳ではありません

Commentsテーブルにnovel_idカラム(FK)やwriter_idカラム(FK)などを追加する

GOOD
テーブル設計は基本的に冗長なデータは持たないようにした方が良いですが、持ってはいけないというルールはありませんし、システム全体を見て持った方が都合が良さそうなら持たせれば良いです。

投稿2021/02/02 10:35

hentaiman

総合スコア6426

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

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

howaito

2021/02/03 01:47

hentaimanさん、回答ありがとうございますm(_ _)m 正規化しずきても最適ではない場合もあるんですね汗 とても勉強になります。ありがとうございます!!
hentaiman

2021/02/03 02:03

それはシステムの仕様によります よく分からないけどやりたい事をやる為には冗長なデータの持ち方するしかない!っていう判断ならNGだけど、冗長にデータを持つ理由を他人に説明して納得させられる程度の考えを持てるのなら冗長に持っても良い
howaito

2021/02/03 09:14

わかりやすく回答頂きありがとうございますm(_ _)m 今後の参考にもさせて頂きます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問