当方、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 でハマらないために知っておきたいこと