こんにちわ、最近SpotifyにハマっているTakaです。さて、今回はLaravelの備忘録として、EloquentでWhereInを使ってデータ検索した場合に、指定した配列の並び順にソートする方法を紹介したいと思います。
なお、Laravelとはなんぞやという方は下の記事を参照してください!
さて、本題に移りますが、例えばEloquentで指定したIDのデータだけをDBから取得したい場合、あらかじめ配列に取得したいデータのIDだけを設定しておいて、whereInを使って実行すれば指定したデータだけ取得できます。その場合のサンプルコードが下記になります。
$ids = array(1,10,5,9,3);
$data = Data::whereIn('id', $ids)->get();
この場合は、Dataモデルで指定したテーブルからIDが「1,10,5,9,3」のデータを取得します。その場合の取得結果がこの配列の並び順に出てくれればいいのですが、バラバラになって出てくる場合があります。これを配列の並び順に取得するサンプルコードが下記になります。
$ids = array(1,3,5,7,9);
$ids_order = implode(',', $ids);
$data = Data::whereIn('id', $ids)->orderByRaw(DB::raw("FIELD(id, $ids_order)"))->get();
気づいた人も多いと思いますが、Eloquentとクエリービルダーの合わせ技ですね。少しタイトル詐欺になってしまい、すいません。
まず、「implode」で配列を文字列に連結して、orderByRawを使ってクエリービルダーで生クエリを使ってあげれば配列の順番通りに取得できます。
なお、DB:rawメソッドは生クエリになりますので、SQLインジェクションには注意して、必ず事前にエスケープ処理をしてください。
2018.02.06追記
ちなみに、orderByRawメソッドもSQL文が書けるので、わざわざDB::rawメソッドを使わなくても大丈夫でした。下のコードでもいけます。こちらの方がスッキリしていていいですね。
$ids = array(1,3,5,7,9);
$ids_order = implode(',', $ids);
$data = Data::whereIn('id', $ids)->orderByRaw("FIELD(id, $ids_order)")->get();
さらに、orderByRaw関数であれば第2引数に配列を指定することでバインドしてくれるということが分かったので、なおさらDB::raw関数を使う意味がなくなりました。
例えば、下記のような感じでコーディングすればLaravel側がバインドしてくれるので、エスケープ作業をする必要がなくなります。
$ids = array(1,3,5,7,9);
$placeholder = '';
foreach ($ids as $key => $value) {
$placeholder .= ($key == 0) ? '?' : ',?';
}
$data = Data::whereIn('id', $ids)->orderByRaw("FIELD(id, $placeholder)",$ids)->get();
これが一番まともなコーディングかもしれません。
しかし、Laravelやっぱり便利だな。
ということで、以上、今回はここまで!Takaでした。また!
この記事のまとめ
- EloquentでwhereInを使った場合に配列の並び順にソートする方法