Laravelで並び替えが上手くいかない時の対処法
Laravelでデータの並び替えが上手くいかない時の対処法
Laravelでデータを綺麗に並べ替えたいとき、数値と文字列が混在していると「何故か期待通りに並ばない…」なんて経験、ありませんか?
私は経験上、何回かあるのですがあまりまとめてくれている記事がないと感じたため、本記事でまとめておこうと思います。
◇ 数値だけのデータ並び替えがうまくいかない場合
例えば、[ "10", "1", "2" ]
のようにDBのデータ型はcharだが、実際は数値しか入っていない場合、昇順で並び替えすると[ "1", "10", "2" ]
のようになります。
これだと1~10の順番で並び替えたい時に困ります...
Eloquentでの解決方法
ここでは、数値として並び替えるために、CAST
を使用します。
データをしっかり数値としてキャストして並べ替えましょう。
// 数値としてキャスト
$models = Model::orderBy(DB::raw('CAST(column_name AS SIGNED)'))
->get();
この方法なら、[ "1", "2", "10" ]
の順にしっかりと整列され、期待通りになります。
数値なら、CAST(... AS INT)
なのでは?と思った方もいるかも知れませんが、
MySQLではCAST(... AS INT)
という構文は認識されないようです。
コレクションメソッドでの解決方法
もし、コレクションメソッドを使って操作するなら、普通に記述しても期待通りに並び替えることができます。
$models = Model::get();
$models = $models->sortBy(function ($item) {
return $item->column_name;
})
->values();
Eloquentの時みたいにCASTしなくても、なぜ上手く並び替えられるのかというと
[ "1", "2", "10" ]
のように文字列であってもsortBy()
の中で暗黙的に数値型に変換され、
比較されているからです。
例: "1"と"10"を比較する際、実際は1と10で比較している
◇ 「文字列 + 数値」が混在している場合
例えば ["TEST-1", "TEST-2", "TEST-10"]
のように、文字列と数値が混ざったデータの並び替えです。たまに出てきた時、「あれ、やり方なんだっけ?」と悩む方も多いはず。
普通の並び替えると["TEST-1", "TEST-10", "TEST-2"]
となってしまいます。
Eloquentでの解決方法
この場合、Eloquentでの並び替えは少しトリッキー。
ここでは文字列の長さ => 辞書順の順番で並び替えを行います。
// 文字列の長さ => 辞書順 の順番で並び替える
$models = Model::orderBy(DB::raw('LENGTH(column_name)'))
->orderBy('column_name')
->get();
昇順の場合、まず文字列の長さで比較することによって、"TEST-10"
は一番後ろになります。
その後、通常のorderBy()
を使って並び替えることにより、["TEST-1", "TEST-2", "TEST-10"]
のように並び替えることができます。
コレクションメソッドでの解決方法
コレクションを使う場合は、PHPの定義済み定数であるSORT_NATURAL
を利用することで、
自然な文字列比較が可能になります。
$models = Model::get();
$models = Model::get();
// PHPの定義済み定数を利用する
$sortedModels = $models->sortBy('column_name', SORT_NATURAL)
->values();
// 別の書き方 (strnatcmp()を利用する)
$sortedModels = $models->sort(function ($a, $b) {
return strnatcmp($a->column_name, $b->column_name);
})
->values();
SORT_NATURAL
やstrnatcmp()
を使うことで、データがキレイに並び変わります。「あれ?なんかソートが変だな…」と思ったら、これで解決できます!
Laravelを使っていると、意外と直面する「並び替え問題」。今回は、この問題の解決方法を紹介しました。ぜひこの記事を参考にして、Laravelでのデータ処理をサクッと実現してください!
また、Laravelの並び替えについて他のテクニックを知っている方、ぜひコメントください。
(多数の方への助けになります)
Discussion