php - Extract subset of fields from within a Laravel collection
I have a Laravel collection like this (approximating using array syntax; the actual data is a Collection
of object
s obtained from an API response, not a local DB):
$rows = [
[
'id': 1,
'name': 'Sue',
'age': 23,
],
[
'id': 2,
'name': 'Joe',
'age': 25,
],
]
I want to extract a subset of the fields:
$subset = [];
foreach ($rows as $row) {
$subset[] = ['name' => $row['name'], 'age' => $row['age']];
}
So that I end up with:
$subset = [
[
'name': 'Sue',
'age': 23,
],
[
'name': 'Joe',
'age': 25,
],
]
What should I use to achieve that instead of the
for
loop?
I found this suggestion, using a higher-order message, which made some kind of sense:
$subset = $rows->map->only(['name', 'age']);
but that just gives me a Collection
of null
values. Expanding it into a conventional map
call produced the same effect. I feel like I want some kind of multipluck
, but I'm not sure what that corresponds to!
Update
It turns out that I was doing this correctly with the higher-order map->only
approach. However, while the items in my collection were a kind of Model
, they were not a subclass or compatible implementation of the Laravel Model
class, and lacked an implementation of the only
method. The author added the method, and now it works as expected.
Answer
Solution:
You were close, but you don't chain map
and only
, and only
doesn't seem to work on a Collection of nested array
s/object
s.
So, for your case, use map()
with a Callback:
$rows = collect([
(object)[
'id' => 1,
'name' => 'Sue',
'age' => 23,
],
(object)[
'id' => 2,
'name' => 'Joe',
'age' => 25,
]
]);
$mapped = $rows->map(function ($row) {
return ['age' => $row->age, 'name' => $row->name];
});
dd($mapped->toArray());
Output of that would be:
array:2 [?�?
0 => array:2 [?�?
"age" => 23
"name" => "Sue"
]
1 => array:2 [?�?
"age" => 25
"name" => "Joe"
]
]
Note: If these are array
s and not object
s, then you'd do $row['age']
and $row['name']
instead of $row->age
and $row->name
. In Laravel, Models are both, and allow either syntax.
References:
https://laravel.com/docs/9.x/collections#method-map
https://laravel.com/docs/9.x/collections#method-only
Edit:
Some alternatives. If you have a Collection
of Model
s, then you can natively do:
$mapped = $rows->map(function ($model) {
return $model->only(['age', 'name']);
});
If you have a Collection
of Collection
s, then you can do:
$mapped = $rows->map(function ($collection) {
return $collection->only(['age', 'name']);
});
And lastly, if you array
s or object
s, you can collect()
and call ->only()
:
$mapped = $rows->map(function ($row) {
return collect($row)->only(['age', 'name']);
});
Source