reverse() on querybuilder get() changes the collection results
Asked Answered
D

3

11

I need to get last 10 records of a table ordered by a data, and reverse them.

This is the code before the reverse:

$eventi = \App\Model::with('relation_1', 'relation_2')
    ->orderBy('data_ora', 'desc')
    ->take(10)
    ->get();

If I log the results I get this:

[{"id":12297,"stato_batteria":null,"data_ora":"2018-05-03 11:40:02" ...

The reverse code is:

$eventi = \App\Model::with('relation_1', 'relation_2')
    ->orderBy('data_ora', 'desc')
    ->take(10)
    ->get()
    ->reverse();

If I log the results I get this:

{"9":{"id":1410,"stato_batteria":null,"data_ora":"2018-04-05 14:16:48" ...

As you can see the collection is changed and I do not know why.

Disentangle answered 3/5, 2018 at 10:13 Comment(7)
What do you mean that the collection has changed? You've called reverse which returns a new collection with the items in reverse order.Plumbiferous
if the collection is not changed, why the 2 collections, written on the log file, are different?Disentangle
Did you expect the two outputs to be the same? If not, what did you expect to happen?Plumbiferous
I expect the 2 collections are the same json object, just reverse. If you see what I get in the log you see you have 2 different objects.Disentangle
I can't see enough data to make that assumption, can you post your full logs for those two calls?Plumbiferous
[{"id":12297,"stato_batteria":null and {"9":{"id":1410,"stato_batteria" are pretty different from the beginning. The first one is a json array, the second one is a json object.Disentangle
It still doesn't show the data that I want to see. The reason you're seeing a JSON object in the second is likely because reverse is preserving keys (which initially were numeric). You're seeing expected behaviour I believe but I need to see more data to be able to comment.Plumbiferous
S
22

Use this to reset the keys:

->reverse()->values();
Snuffbox answered 3/5, 2018 at 10:43 Comment(1)
Finally I got an answer! Thanks! Only reverse() doesn't work properly.Reata
P
6

When you do this:

$eventi = \App\Model::with('relation_1', 'relation_2')
    ->orderBy('data_ora', 'desc')
    ->take(10)
    ->get();

You get a Collection object, containing those values. The keys of the values in the underlying array will be numeric, i.e. 0, 1, 2, ... 9. Now when you're doing:

$eventi = \App\Model::with('relation_1', 'relation_2')
    ->orderBy('data_ora', 'desc')
    ->take(10)
    ->get()
    ->reverse();

You're getting the same collection back, in reverse order. The reverse method creates a new collection, but preserves the keys of the original collection. So in this case you'll be seeing the last item, first and the keys will be 9, 8, 7, ... 0. In PHP, if your array keys aren't integers, in ascending order starting from 0, it is assumed to be an associative array. So when you're outputting your collection as JSON you're seeing it represented as an object.

A way to ignore the keys in the collection is to use values, so that a new collection is created (with ascending numeric keys i.e. 0, 1, 2, ... 9), only with the values of the initial collection:

$eventi = \App\Model::with('relation_1', 'relation_2')
    ->orderBy('data_ora', 'desc')
    ->take(10)
    ->get()
    ->reverse()
    ->values();
Plumbiferous answered 3/5, 2018 at 10:53 Comment(1)
Thanks, it is what I needed.Disentangle
K
0

as mentioned in collection documentation of laravel, when u apply reverse method to a collection, the collection order will change.

in ur case here u get ur data collection order by data_ora and desc,

when u apply reverse after get, that means u will reverse the collection to be ordered by data_ora but ASC not DESC.

in other words, the first element of collection will be the last ...

check the laravel documentation here reverse method

Kindle answered 3/5, 2018 at 10:24 Comment(1)
I wrote what I get if I log the 2 collections, and they are 2 different json objects.Disentangle

© 2022 - 2024 — McMap. All rights reserved.