Laravel 6.x Eloquent优化:避免foreach查询及字段拼接问题
Hey there! Let's tackle your Eloquent optimization questions one by one—these are super common tweaks that'll help you ditch those nested loops and clean up your code:
1. What's the difference between Statuses::get() and Statuses::all()?
At a glance, both return all records from the statuses table as a Laravel Collection, but there's a key difference in flexibility:
Statuses::all()is a static model method that fetches all unfiltered records directly. You can't chain query clauses likewhere()ororderBy()before it—it's a one-and-done call. Under the hood, it actually callsget(), but skips the query builder setup.Statuses::get()is a query builder method, which means you can add constraints first to customize your results. For example:// Fetch only active statuses, sorted by title $activeStatuses = Statuses::where('is_active', true)->orderBy('status_title')->get();
Stick with all() when you truly need every record with no filters, and use get() whenever you need to narrow down or sort your data first.
2. How to get a one-dimensional [id => status_title] array for dropdowns?
You were close with map, but pluck() is the perfect tool for this—it's built explicitly to create key-value pairs:
$statusOptions = Statuses::pluck('status_title', 'id')->all();
pluck()takes two arguments: first the value you want (herestatus_title), then the key (hereid).- Calling
all()converts the Collection to a plain PHP array. If you're using this in a Blade dropdown, you can even skipall()—Blade handles Collections seamlessly inForm::select()or native<select>elements.
Your map->only() approach returned a Collection of arrays (like [{id: 1, status_title: "..."}, ...]), which isn't the flat key-value structure you need for dropdowns. pluck() cuts straight to the format you want.
3. How to create an array in [id => status_title - status_outcome] format?
The issue with your original query was wrapping column names in single quotes inside CONCAT—that made MySQL treat them as literal strings instead of pulling values from the table. Here's the fixed version using SQL-level concatenation:
Option 1 (cleanest with selectRaw):
$combinedStatuses = Statuses::selectRaw("id, CONCAT(status_title, ' - ', status_outcome) AS combined_status") ->pluck('combined_status', 'id') ->all();
Option 2 (using DB::raw in a standard select):
use Illuminate\Support\Facades\DB; $combinedStatuses = Statuses::select( 'id', DB::raw("CONCAT(status_title, ' - ', status_outcome) AS combined_status") ) ->pluck('combined_status', 'id') ->all();
Why your original code failed:
- Single quotes around
'status_title'made MySQL concatenate the string "status_title" instead of the column's actual value. pluck()only accepts up to two arguments (value, key), so passing more would throw an error. Aliasing your concatenated value withAS combined_statusletspluck()reference it correctly.
If you ever need more complex string manipulation that's easier to handle in PHP, you can use mapWithKeys()—though the SQL approach is better for performance with large datasets:
$combinedStatuses = Statuses::all()->mapWithKeys(function ($status) { return [$status->id => "{$status->status_title} - {$status->status_outcome}"]; })->all();
内容的提问来源于stack exchange,提问作者Sherry

