当方、Laravel初心者です。
Eloquentモデル
をクエリビルダのjoin()
を使って関係するテーブルのカラムを使って絞り込んだら、
検索対象じゃないモデルのインスタンスが返ってきて小一時間悩みました。
まとめ
Eloquentモデル
をクエリビルダのjoin()
を使ってインスタンスを取得したら、
id
というカラムが複数存在したため、
想定外のインスタンスが返ってきた。
↓
同じカラム名はLaravel内の処理で上書きされる。
Select()
で取得するカラムを絞ろう!
詳細
たとえばこんなコード。
$searched_posts = Post::join('comments', 'posts.id', '=', 'comments.posts_id')
->where('comments.text', 'like', '%あいうえお%')->get();
posts
テーブルにもcomments
テーブルにも「id
」というカラムがある前提です。
上記のコードをSQLに変換されると多分こんな感じになります。
select * from posts
inner join comments on posts.id = comments.post_id
where comments.text LIKE '%あいうえお%';
仮にSQLの実行結果が以下のような感じだったとします。
| id|post_content|id|text|
|:--|:--|:--|:--|:--|
| 1|あああ|2|あいうえお|
| 3|ううう|3|あいうえお|
| 5|おおお|4|あいうえお|
これでPost
モデルのインスタンスが3つ取れて、
post_content
はそれぞれ「あああ」「ううう」「おおお」
となるんだろうな とおもったら
なぜか全然違うPostが返ってきました。
そうです。
id
カラムが重複して存在するため、
posts.id
をcomments.id
が上書きしてしまい、
id
が2
,3
,4
であるPost
がモデルインスタンスとして取得されてしまいました。
解決策
selectで取ってくるカラムを絞る。
$searched_posts = Post::select('posts.*')->join('comments', 'posts.id', '=', 'comments.posts_id')
->where('comments.text
', 'like', '%あいうえお%')->get();
select('posts.*')
のように、取得するカラムを絞り込むことで、id
というカラムが重複しないようにしましょう。
こういうハマりポイントは知っていればすぐ解決できるのに、知らないと結構はまってしまいますよね。
Laravelを覚えるにあたって先にハマりポイントを押さえておこうと思いました
そもそもクエリビルダのJoinを使って検索をするっていうのがイケてないっぽいので
よりよい方法があれば教えていただきたく思います。
whereHas()
を使うといいのかな?
Post::whereHas('Comment', function($comment){
$comment->where('text', 'like', '%あいうえお%');
以上、お役に立てれば幸いです
参考
laravelのクエリビルダでJOINしたら、同名カラムの値が上書きされるという事案発生
Laravel Eloquent でハマらないために知っておきたいこと