Laravel grouped collection returns object instead of array
Asked Answered
A

8

7

I have the following query

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json([
    'outings' => $outings
], 200);

The response is returning an object and I need it to return an array As you can see, outings is an object and not an array

How can I get outings to be an array instead of an object.

If I don't group the collection and just do

Outing::all();

It will return an array rather than an object. The Group by is doing something weird.

If I DD($outings) it does in fact return a collection, so I think it's odd that it gets cast to an object when returned to the browser rather than an array.

Below is the output when I DD($outings->toArray())

enter image description here

Thanks

Airway answered 28/6, 2018 at 15:53 Comment(12)
just send it return response()->json($outings, 200);Guggenheim
Thanks @rkj, however that still returns an object to the browser.Airway
Add toArray() to $outings. So it will be $outings->toArray();Electrotype
It is worth nothing Eloquent Resources.Postman
@bak87, That was the first thing I tried, it still returns an object. ThanksAirway
@wild-beard I am using a resource but simplified it here to make it easier to read. I Pass my query through the resource then call group by on that.Airway
@KyleReierson Can you show us the output when you try dd($outings->toArray()) after the grouping?Plasmasol
@user3574492, I have attached an image of the dd($outings->toArray()) Thanks!Airway
@KyleReierson How are you seeing the response? Chrome dev tools?Plasmasol
@Plasmasol Yes Chrom dev toolsAirway
@KyleReierson i have updated answer, can you try it.Guggenheim
I think that is because you are sending the response as Json.Electrotype
G
5

If you want array then use this

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
})->map(function($item){
    return $item->all();
});

return response()->json($outings, 200);

If you want date as key then

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json($outings->toArray(), 200);
Guggenheim answered 28/6, 2018 at 16:30 Comment(5)
That will still return an array of objectsPlasmasol
That works! However I need to keep the date as the key in the groupings. array_values resets them to 0,1,2 etcAirway
if you keep the date as groupings then it will return you object againGuggenheim
@KyleReierson you either get array or if you want date as key then you must have object because associative array converted to json object.Guggenheim
Ah, duh. Thanks for your help! I was able to work with this and get the data in the format I need after using array_valuesAirway
C
19

Use array_values($array) to force an associative array into a JSON array. You will lose any key names this way, however.

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json([
    'outings' => array_values($outings)
], 200);

No one has really explained why this happens.

In JavaScript/JSON, arrays are just collections of values, they are keyed but the key is always numerical in sequence.

In PHP, arrays are collections of "key" => "value" pairs, the key can be anything (integer or string) but arrays can generally be considered "associative" (where the key is non-numerical, or numerical but not in sequence) or "non-associative" (where the key is numerical AND in sequence (similar to JS arrays).

When it comes to encoding a PHP array as JSON, say an array has keys that are non-numeric OR the keys are numeric but not in sequential order (e.g. 0, 1, 2, 4, 5, 8, 10) - these types of arrays are not compatible with JavaScript/JSON arrays. In this case, the array is converted into an object to preserve the keys. To force the array to be converted into an array, you must convert the array into a non-associative array (numerical sequenced keys), PHP has the function array_values to help with this.

Caloric answered 31/10, 2019 at 2:34 Comment(2)
i like the explanation. makes a lot of sense 👍🏼Ramsdell
Thank you so much for this explanation, especially this part: "OR the keys are numeric but not in sequential order"! I spent so much time trying to figure out why one set of results was returning as an array, but the other one as an object.Illiberal
K
7

Use ->values()

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json([
    'outings' => $outings->values()
], 200);
Kay answered 2/12, 2021 at 4:38 Comment(2)
you saved my day!Vulgarian
This works for me, thank you! In my case, my iteration of collection modifies the keys of each item - which is the cause of rendering return as object, not array. - thus ->values() is needed for resetting keys in consecutive order. values()Harvard
G
7

On Laravel 8 using Inertia.js with Vue3, I ran into a similar issue. I was trying to return an array of objects Array<{label, name}>

The way I solved it was

return collect($myArray)->map(function($key, $value) {
   return [
      'name' => $value,
      'label' => $key
    ];
   })->values(); // <---- this guy 
Goeger answered 11/4, 2022 at 17:27 Comment(1)
Yes, that did the trick for me! Had a Collection with Collections inside. Needed a return value of Collection as well. Using ->values() did exactly what I needed. When using ->toArray() as suggested in other answers, the return value becomes an array instead of a Collection.Shell
G
5

If you want array then use this

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
})->map(function($item){
    return $item->all();
});

return response()->json($outings, 200);

If you want date as key then

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json($outings->toArray(), 200);
Guggenheim answered 28/6, 2018 at 16:30 Comment(5)
That will still return an array of objectsPlasmasol
That works! However I need to keep the date as the key in the groupings. array_values resets them to 0,1,2 etcAirway
if you keep the date as groupings then it will return you object againGuggenheim
@KyleReierson you either get array or if you want date as key then you must have object because associative array converted to json object.Guggenheim
Ah, duh. Thanks for your help! I was able to work with this and get the data in the format I need after using array_valuesAirway
U
1

on laravel 8

 public function index()
    {
        $products = Product::all()->toArray();
        return array_reverse($products);      
    }
Unthinkable answered 10/9, 2021 at 22:22 Comment(0)
P
0

Try doing:

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
});

return response()->json([
    'outings' => $outings->toArray()
], 200);
Plasmasol answered 28/6, 2018 at 16:12 Comment(2)
That was one of the first things I tried, still returns an objectAirway
@KyleReierson Can you show us the output when you try dd($outings->toArray()) after the grouping?Plasmasol
S
0
$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
})->toArray();

return response()->json([
    'outings' => $outings
], 200);

Have a look at toArray()

Also Try

$outings = Outing::all()->groupBy(function ($item) {
   return Carbon::parse($item['start'])->format('m/d/Y');
})->toArray();

return response()->json([
    'outings' => json_encode($outings)
], 200);
Shod answered 28/6, 2018 at 16:12 Comment(2)
That was one of the first things I tried, still returns an objectAirway
@KyleReierson try (\Arrayable) $outings see what happensShod
C
0

If you are looking to go from a collection of objects to an array of arrays, the sneaky way to do it is json encode/decode. That'll turn any object in there to an array. So if you do something like:

$my_collection = People::get(['id', 'name']);
$my_array = json_decode(json_encode($my_collection), true);

You'll go from:

Illuminate\Database\Eloquent\Collection { 
  App\Models\People{id: 123, name: "steve"}, 
  App\Models\People{id: 456, name: "sara"},
  ...
}

to:

[ 
  ["id" => 123, "name" => "steve"], 
  ["id" => 456, "name" => "sara"],
  ...
]
Cupp answered 25/1, 2023 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.