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

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