7

If I run $collection->filter(myFilter), Laravel does this annoying thing of adding keys to each model in the collection like so:

{
    "4": {
        "myObject": "data"
    },
    "7": {
        "myObject": "data"
    }
}

How can I get rid of the "4" and "7" so it's an array of my objects?

My code that runs is:

$obj = Cars::with('brand')->orderBy('id')->get();

return $obj->filter(function($value, $key)
{
    return $value->display == true;
});
patricus
  • 59,488
  • 15
  • 143
  • 145
tgun926
  • 1,573
  • 4
  • 21
  • 37
  • 1
    I feel like `flatten()` might do what you're after, but you're going to need to provider some more example code to see how you're getting this output. – Dwight Feb 12 '17 at 00:38
  • Yeah, `flatten()` should do the trick – manniL Feb 12 '17 at 00:40
  • 1
    @Dwight added code in - flatten worked. Feel free to add an answer for me to accept. – tgun926 Feb 12 '17 at 00:44
  • @tgun926 While `flatten()` happens to work in this case, `values()` is the appropriate method to use. I have added an answer with an explanation. – patricus Feb 12 '17 at 05:36

2 Answers2

24

The issue is that the filter() method does not rekey the underlying collection array. So, the Collection is still representing an array, it is just that your array looks like this:

[
    4 => Object4,
    7 => Object7,
]

While this is a perfectly valid array in PHP, this is not a proper array in JSON. Since this cannot be represented as an array in JSON, it is converted to an object in JSON.

In order to get this properly represented as an array in JSON, you just need to rekey the Collection array. The proper method for this is the values() method. All it does is call array_values on the underlying array. This will turn the above array in this:

[
    0 => Object4,
    1 => Object7,
]

Now, this is a proper numerically indexed array that JSON can understand and will treat as an array instead of an object.

While flatten may work for this particular case (your Collection is a collection of Eloquent Models), it is not actually the correct method, and may lead to unintended consequences. Additionally, it will perform a lot of extra logic that is not needed. Your best bet is to use the proper method for what you are trying to achieve, and that is the values() method.

$obj = Cars::with('brand')->orderBy('id')->get();

return $obj->filter(function($value, $key)
    {
        return $value->display == true;
    })
    ->values();
patricus
  • 59,488
  • 15
  • 143
  • 145
  • 3
    Ah yeah, @patricus is right - `values` is the correct method to use here, and as mentioned it should be more performant. Totally forgot about that method, good to be reminded. This should be the accepted answer. – Dwight Feb 12 '17 at 04:51
  • @patricusMaybe you can help me. Look at this : https://stackoverflow.com/questions/51488623/how-can-i-convert-array-two-dimensional-to-collection-laravel – moses toh Jul 24 '18 at 02:51
5

Calling flatten() on your collection should remove the keys and merge all their values up into a single collection.

Dwight
  • 12,120
  • 6
  • 51
  • 64