Filtering Eloquent collection data with $collection->filter()

Tenzoru picture Tenzoru · Feb 23, 2014 · Viewed 79.7k times · Source

I'm trying to filter the following collection using the collection filter() method:

$collection = Word::all();

where the JSON output looks like this:

[
{
"id": "1",
"word": "dog",
"phonetic": "dog",
"mean": "pies",
"assoc": "some example text",
"author_id": "3",
"user_id": "3"
},
{
"id": "2",
"word": "sun",
"phonetic": "sun",
"mean": "słońce",
"assoc": "lorem ipsun dolor sit amet",
"author_id": "3",
"user_id": "2"
}, ...
]

However, when filtering the collection:

$filtered_collection = $collection->filter(function($item)
    {
        if($item->isDog())
        {
            return $item;
        }
 });

The filtered collection JSON output will look like this:

 {"1":
 {
 "id": "1",
 "word": "dog",
 "phonetic": "dog",
 "mean": "pies",
 "assoc": "some example text",
 "author_id": "3",
 "user_id": "3"
 },
 "2":
 {
 "id": "2",
 "word": "sun",
 "phonetic": "sun",
 "mean": "słońce",
 "assoc": "lorem ipsun dolor sit amet",
 "author_id": "3",
 "user_id": "2"
 }}

How can I keep the original JSON output when filtering a collection? I'd like to have an array of my Eloquent model instances when filtering the original collection . Thanks in advance :)

Answer

Joseph Silber picture Joseph Silber · Feb 23, 2014

The collection's filter method calls array_filter on the underlying array, which, according to the PHP docs, preserves the array keys. This then results in your array being converted to a JavaScript object instead of an array.

Call values() on your collection to reset the keys on the underlying array:

$filtered_collection = $collection->filter(function ($item) {
    return $item->isDog();
})->values();

Side note: in newer versions of Laravel, you can use a higher order message to shorten the above into this:

$filtered_collection = $collection->filter->isDog()->values();