When working with Laravel’s Collection class, several of its methods allow you to use a short hand called dot-notation to access nested values.
Here’s an example of a structure that has nested data we want to pull out and echo.
$employees = collect([
[
'name' => 'Terry',
'login' => [
'username' => 'thelms@example.com',
],
],
[
'name' => 'Vic',
'login' => [
'username' => 'vchance@example.com',
],
],
]);
To access the username, we use the dot-notation key string “login.username”.
echo 'Users: ' . $employees->implode('login.username', '; ');
// Users: thelms@example.com; vchance@example.com
But which Laravel Collection methods support dot-notation? Not all of them.
TL;DR
Most methods that accept key names respect dot-notation. The list of those that don’t is short: forget
, get
, has
, only
, prepend
, put
. Some other methods only accept callbacks, such as map
.
Any method that accepts the same parameters as where($key, $operator, $value)
will also respect dot-notation.
Only pluck
and groupBy
use the array-wildcard * correctly. The others will give wrong results.
Methods that respect dot-notation
- average
- avg
- contains
- containsStrict
- duplicates
- duplicatesStrict
- every
- except
- firstWhere
- groupBy
- implode
- sum
- unique
- uniqueStrict
- where
- whereBetween
- whereIn
- whereInStrict
- whereNotBetween
- whereNotIn
- whereNotInStrict
- whereStrict
average
Laravel Docs: average
Dot-notation Example:
$students = collect([
[
'name' => 'Carol',
'assessment' => [
'created_at' => '2019-09-06',
'score' => 98,
],
],
[
'name' => 'Carl',
'assessment' => [
'created_at' => '2019-09-05',
'score' => 97,
],
],
[
'name' => 'Coral',
'assessment' => [
'created_at' => '2019-09-06',
'score' => 99,
],
],
]);
echo "Average Score: " . $students->average('assessment.score');
// Average Score: 98
This method does not play nice with *.
avg
Alias for average.
contains
Laravel Docs: contains
Dot-notation Example:
$owners = collect([
[
'name' => 'Drake',
'books' => [
'hates' => 'Of Mice And Men',
'likes' => 'Great Expectations',
],
],
[
'name' => 'Brake',
'books' => [
'likes' => 'Men Explain Things To Me',
],
],
[
'name' => 'Blake',
'books' => [
'likes' => 'Snowcrash',
'hates' => 'Wall-E Novelization',
],
],
]);
$owners->contains('books.likes', 'Snowcrash');
// true
This method accepts the same parameters as where.
This method does not play nice with *.
containsStrict
Strict-comparison version of contains.
duplicates
Laravel Docs: duplicates
Dot-notation Example:
$employees = collect([
[
'name' => 'Evangeline',
'position' => [
'title' => 'Developer',
'started_at' => '2004-03-02',
],
],
[
'name' => 'Edwin',
'position' => [
'title' => 'Developer',
'started_at' => '2008-12-01',
],
],
[
'name' => 'Erica',
'position' => [
'title' => 'SysAdmin',
'started_at' => '2015-09-12',
],
],
]);
$employees->duplicates('position.title');
// [2 => 'Developer']
Another undocumented feature of duplicates
is that the largest key is preserved for each value. Use values to reset the keys.
This method does not play nice with *.
duplicatesStrict
Strict-comparison version of duplicates.
every
Laravel Docs: every
Dot-notation Example:
$swans = collect([
[
'name' => 'Fredrico',
'appearance' => [
'color' => 'white',
'size' => 'large',
],
],
[
'name' => 'Ferdinand',
'appearance' => [
'color' => 'white',
'size' => 'small',
],
],
[
'name' => 'Fabian',
'appearance' => [
'color' => 'black',
'size' => 'tiny',
],
],
]);
$swans->every('appearance.color', 'white');
// false
This method accepts the same parameters as where.
This method does not play nice with *.
except
Laravel Docs: except
Dot-notation Example:
$user = collect([
'name' => 'Gravely',
'created_at' => '2019-09-09',
'photo' => [
'url' => 'http://lorempixel.com/400/200/',
'width' => 400,
'height' => 200,
],
]);
$user->except('photo.width', 'photo.height', 'created_at');
// [
// 'name' => 'Gravely',
// 'photo' => [
// 'url' => 'http://lorempixel.com/400/200/',
// ],
// ]
This method does not play nice with *.
firstWhere
Laravel Docs: firstWhere
Dot-notation Example:
$houses = collect([
[
'name' => 'Chateau Louisiana',
'owner' => [
'name' => 'Hurkey',
'owner_since' => '2019-08-07',
],
],
[
'name' => 'Chateau Detritus',
'owner' => [
'name' => 'Hardey',
'owner_since' => '2019-08-07',
],
],
]);
$houses->firstWhere('owner.name', 'Hardey');
// [
// 'name' => 'Chateau Detritus',
// 'owner' => [
// 'name' => 'Hardey',
// 'owner_since' => '2019-08-07',
// ],
// ]
This method accepts the same parameters as where.
This method does not play nice with *.
groupBy
Laravel Docs: groupBy
Dot-notation Example:
$birds = collect([
[
'type' => 'Duck',
'traits' => [
'feet' => 'webbed',
'bill' => 'broad',
],
],
[
'type' => 'Blue jay',
'traits' => [
'feet' => 'non-webbed',
'bill' => 'slender',
],
],
[
'type' => 'Goose',
'traits' => [
'feet' => 'webbed',
'bill' => 'slender',
],
],
]);
$birds->groupBy('traits.feet');
// [
// 'webbed' => [
// [
// 'type' => 'Duck',
// 'traits' => [
// 'feet' => 'webbed',
// 'bill' => 'broad',
// ],
// ],
// [
// 'type' => 'Goose',
// 'traits' => [
// 'feet' => 'webbed',
// 'bill' => 'slender',
// ],
// ],
// ],
// 'non-webbed' => [
// [
// 'type' => 'Blue jay',
// 'traits' => [
// 'feet' => 'non-webbed',
// 'bill' => 'slender',
// ],
// ],
// ],
// ]
This method plays nice with *. See What about *? below for an example.
implode
Laravel Docs: implode
Dot-notation Example:
$employees = collect([
[
'name' => 'Terry',
'login' => [
'username' => 'thelms@example.com',
'password_hash' => '352663636',
],
],
[
'name' => 'Vic',
'login' => [
'username' => 'vchance@example.com',
'password_hash' => '84888B277',
],
],
]);
echo 'Users: ' . $employees->implode('login.username', '; ');
// Users: thelms@example.com; vchance@example.com
This method does not play nice with *.
keyBy
Laravel Docs: keyBy
Dot-notation Example:
$parks = collect([
[
'name' => 'Yosemite',
'authority' => [
'chief' => 'Gilbert',
'technical' => 'Gandry',
],
],
[
'name' => 'Yellow Stone',
'authority' => [
'chief' => 'Gertrude',
'technical' => 'Gillian',
],
],
]);
$parks->keyBy('authority.chief');
// [
// 'Gilbert' => [
// 'name' => 'Yosemite',
// 'authority' => [
// 'chief' => 'Gilbert',
// 'technical' => 'Gandry',
// ],
// ],
// 'Gertrude' => [
// 'name' => 'Yellow Stone',
// 'authority' => [
// 'chief' => 'Gertrude',
// 'technical' => 'Gillian',
// ],
// ],
// ]
This method does not play nice with *, but the similar groupBy does.
max
Laravel Docs: max
Dot-notation Example:
$charts = collect([
[
'name' => 'WENUS',
'range' => [
'highest_value' => 59,
'lowest_value' => 11,
],
],
[
'name' => 'Top 40',
'range' => [
'highest_value' => 40,
'lowest_value' => 1,
],
],
]);
$charts->max('range.highest_value');
// 59
This one doesn’t return the element that has the max value, but instead returns the value itself.
This method does not play nice with *.
median
Laravel Docs: median
Dot-notation Example:
$lakes = collect([
[
'name' => 'Blue Lake',
'customer_ratings' => ['high' => 100, 'low' => 98],
],
[
'name' => 'Moose Lake',
'customer_ratings' => ['high' => 78, 'low' => 15],
],
[
'name' => 'Sad Lake',
'customer_ratings' => ['high' => 99, 'low' => 80],
],
]);
$lakes->median('customer_ratings.high');
// 99
This one doesn’t return the element that has the median value, but instead returns the value itself.
This method does not play nice with *.
min
Laravel Docs: min
Dot-notation Example:
$racing_crabs = collect([
[
'name' => 'Charlie',
'times' => ['fastest' => 27, 'slowest' => 51],
],
[
'name' => 'Ban mi',
'times' => ['fastest' => 40, 'slowest' => 45],
],
[
'name' => 'Gator Hater',
'times' => ['fastest' => 28, 'slowest' => 39],
],
]);
$racing_crabs->min('times.fastest');
// 27
This one doesn’t return the element that has the min value, but instead returns the value itself.
This method does not play nice with *.
mode
Laravel Docs: mode
Dot-notation Example:
$homes = collect([
[
'neighborhood' => 'Clampet Estates',
'details' => [
'type' => 'ranch',
'area' => 2100,
],
],
[
'neighborhood' => 'Fletcher Pavilion',
'details' => [
'type' => 'ranch',
'area' => 3000,
],
],
[
'neighborhood' => 'Terrence Terraces',
'details' => [
'type' => 'bungalow',
'area' => 1200,
],
],
]);
$homes->mode('details.type');
// ['ranch']
This one doesn’t return the element that has the mode value, but instead returns the value itself in an array. If multiple values could be considered the mode, they are all present in the array.
This method does not play nice with *.
partition
Laravel Docs: partition
Dot-notation Example:
$cart_items = collect([
[
'description' => 'Cake',
'price' => [
'base' => 4.00,
'tax' => 0.28,
],
],
[
'description' => 'Rice',
'price' => [
'base' => 1.50,
'tax' => 0.00,
],
],
[
'description' => 'Limburger',
'price' => [
'base' => 10.00,
'tax' => 0.00,
],
],
]);
$cart_items->partition('price.base', '>', 3.00);
// [
// [
// [
// 'description' => 'Cake',
// 'price' => [
// 'base' => 4.00,
// 'tax' => 0.28,
// ],
// ],
// [
// 'description' => 'Limburger',
// 'price' => [
// 'base' => 10.00,
// 'tax' => 0.00,
// ],
// ],
// ],
// [
// [
// 'description' => 'Rice',
// 'price' => [
// 'base' => 1.50,
// 'tax' => 0.00,
// ],
// ],
// ],
// ]
This method accepts the same parameters as where.
This method does not play nice with *.
pluck
Laravel Docs: partition
Dot-notation Example:
$equipment = collect([
[
'description' => 'balls',
'location' => [
'building' => 4,
'bin' => 17,
],
],
[
'description' => 'pads',
'location' => [
'building' => 2,
'bin' => 10,
],
],
]);
$equipment->pluck('location.building');
// [4, 2]
This method plays nice with *. See What about *? below for an example.
pull
Laravel Docs: pull
Dot-notation Example:
$system = collect([
'name' => 'rothchild-1',
'tasks' => [
[
'commmand' => 'start-jml',
],
[
'commmand' => 'start-interest-blt',
],
],
]);
$system->pull('tasks.0');
// [
// 'commmand' => 'start-jml',
// ]
// AND
// $system = [
// 'name' => 'rothchild-1',
// 'tasks' => [
// 1 => [
// 'commmand' => 'start-interest-blt',
// ],
// ],
// ]
This method does not play nice with *.
Notice in this example that we pulled 0
from the tasks
array, but the
remaining element did not change its key. It’s still at 1
.
some
Alias for contains.
sortBy
Laravel Docs: sortBy
Dot-notation Example:
$vegetables = collect([
[
'description' => 'carrots',
'ratings' => [
'satisfaction' => 5,
'production' => 8,
],
],
[
'description' => 'broccoli',
'ratings' => [
'satisfaction' => 7,
'production' => 4,
],
],
[
'description' => 'potate',
'ratings' => [
'satisfaction' => 3,
'production' => 5,
],
],
]);
$vegetables->sortBy('ratings.satisfaction');
// [
// [
// 'description' => 'potate',
// 'ratings' => [
// 'satisfaction' => 3,
// 'production' => 5,
// ],
// ],
// [
// 'description' => 'carrots',
// 'ratings' => [
// 'satisfaction' => 5,
// 'production' => 8,
// ],
// ],
// [
// 'description' => 'broccoli',
// 'ratings' => [
// 'satisfaction' => 7,
// 'production' => 4,
// ],
// ],
// ]
This method does not play nice with *.
sortByDesc
Reverse version of sortBy.
sum
Laravel Docs: sum
Dot-notation Example:
$bugs = collect([
[
'description' => 'Customer explodes',
'time' => [
'alloted' => 5,
'spent' => 6,
],
],
[
'description' => 'Button incorrectly colored',
'time' => [
'alloted' => 1,
'spent' => 3,
],
],
]);
$bugs->sum('time.spent');
// 9
This method does not play nice with *.
unique
Laravel Docs: unique
Dot-notation Example:
$aliens = collect([
[
'name' => 'Slime Species',
'quick_facts' => [
'population' => 1.4e10,
'home' => 'Gangnam 4',
],
],
[
'name' => 'Dog-like Species',
'quick_facts' => [
'population' => 3.1e8,
'home' => 'Kilroy 2',
],
],
[
'name' => 'Cat-like Species',
'quick_facts' => [
'population' => 2.8e7,
'home' => 'Kilroy 2',
],
],
]);
$aliens->unique('quick_facts.home');
// [
// [
// 'name' => 'Slime Species',
// 'quick_facts' => [
// 'population' => 1.4e10,
// 'home' => 'Gangnam 4',
// ],
// ],
// [
// 'name' => 'Dog-like Species',
// 'quick_facts' => [
// 'population' => 3.1e8,
// 'home' => 'Kilroy 2',
// ],
// ],
// ]
This method does not play nice with *.
uniqueStrict
Strict-comparison version of unique.
where
Laravel Docs: where
Dot-notation Example:
$countries = collect([
[
'name' => 'USA!',
'people' => [
'population' => 300e6,
'average_age' => 38.1,
],
],
[
'name' => 'Canada',
'people' => [
'population' => 37e6,
'average_age' => 40.8,
],
],
[
'name' => 'Bolivia',
'people' => [
'population' => 11e6,
'average_age' => 23.1,
],
],
]);
$countries->where('people.population', '<', 100e6);
// [
// [
// 'name' => 'Canada',
// 'people' => [
// 'population' => 37e6,
// 'average_age' => 40.8,
// ],
// ],
// [
// 'name' => 'Bolivia',
// 'people' => [
// 'population' => 11e6,
// 'average_age' => 23.1,
// ],
// ],
// ]
This method does not play nice with *.
whereBetween
Laravel Docs: whereBetween
Dot-notation Example:
$snakes = collect([
[
'name' => 'Jim',
'traits' => [
'breed' => 'black racer',
'length' => 14,
],
],
[
'name' => 'Bruce O\'Leary',
'traits' => [
'breed' => 'antillean',
'length' => 1,
],
],
]);
$snakes->whereBetween('traits.length', [10, 20]);
// [
// [
// 'name' => 'Jim',
// 'traits' => [
// 'breed' => 'black racer',
// 'length' => 14,
// ],
// ],
// ]
This method does not play nice with *.
whereIn
Laravel Docs: whereIn
Dot-notation Example:
$bears = collect([
[
'name' => 'Grizzly',
'ratings' => [
'danger' => 'high',
'cuddliness' => 'low',
],
],
[
'name' => 'Teddy',
'ratings' => [
'danger' => 'low',
'cuddliness' => 'high',
],
],
]);
$bears->whereIn('ratings.danger', ['high', 'medium']);
// [
// [
// 'name' => 'Grizzly',
// 'ratings' => [
// 'danger' => 'high',
// 'cuddliness' => 'low',
// ],
// ],
// ]
This method does not play nice with *.
whereInStrict
Strict-comparison version of whereIn.
whereNotBetween
Reverse version of whereBetween.
whereNotIn
Reverse version of whereIn.
whereNotInStrict
Reverse and strict-comparison version of whereIn.
whereStrict
Strict-comparison version of where.
Methods that do NOT respect dot-notation
These methods work directly on a Collection’s internal array without checking to see whether the keys passed in contain dots.
forget
get
has
only
prepend
put
PHP operations that don’t respect dot-notation:
Similar to the above methods these native PHP operations only act directly on the internal array and do not change their behavior for a key with dots.
isset($collection['key.key'])
echo $collection['key.key']
$collection['key.key'] = 'value'
unset($collection['key.key'])
echo $collection->{'key.key'}
What about *?
When we want to act on every element of a nested array, dot-notation lets us use an asterisk (*) wildcard, with some caveats:
- The element * searches through must be an array or Collection.
- Each use of * creates an array or null result in the core code, and most methods cannot deal with it.
- If something in the key path is missing, the result Collection will have nulls in some spots instead of arrays.
Because of these caveats, the only two methods that support * well are pluck and groupBy. Other methods will simply return bad results.
$players = collect([
[
'name' => 'XDestroyY',
'achievements' => [
[
'description' => 'Collect 400 Chipples',
'difficulty' => 2,
],
[
'description' => 'Pass the Mork',
'difficulty' => 5,
],
[
// why is this one empty? ¯\_(ツ)_/¯
],
],
],
[
'name' => 'BunnyNewb',
// no achievements
],
]);
$players->pluck('achievements.*.description')
// [
// [
// "Collect 400 Chipples",
// "Pass the Mork",
// null,
// ],
// null,
// ]
You may need to flatten
and/or filter
the Collection to get the results you want.
$players->pluck('achievements.*.description')->flatten()->filter();
// [
// "Collect 400 Chipples",
// "Pass the Mork",
// ]
When the groupBy
method encounters a *, it will group each item into all the group names that result.
$players->groupBy('achievements.*.description');
// [
// 'Collect 400 Chipples' => [
// [
// 'name' => 'XDestroyY',
// ... the whole array ...
// ],
// ],
// 'Pass the Mork' => [
// [
// 'name' => 'XDestroyY',
// ... the whole array ...
// ],
// ],
// '' => [
// [
// 'name' => 'BunnyNewb',
// ... the whole array ...
// ],
// [
// 'name' => 'XDestroyY',
// ... the whole array ...
// ],
// ],
// ]
Notice in the above example that the nulls that pluck
would produce were turned into ''
and used as a group name.
Some methods that cannot use * can still be applied elegantly by using the * in a pluck
call first. Some that work well that way are average
, contains
, duplicates
, every
, implode
, max
, median
, min
, mode
, and sum
.
$players->contains('achievements.*.description', 'Collect 400 Chipples')
// false
$players
->pluck('achievements.*.description')
->flatten()
->contains('Collect 400 Chipples')
// true