georgefromohio's avatar

Cursor Pagination on Eloquent Models

Has anyone got enough time with Laravel 8.4.*? Particularly the cursorPaginate method? I'm pulling my hair out and any help would be appreciated.

I've got two scenarios:

People::cursorPaginate($request->query('limit'))

This works great with the links to the next page and previous pages. However!! When I add an orderBy or orderByDesc as mentioned in the docs, none of the links work.

People::orderByDesc('created_at')->cursorPaginate($request->query('limit'))

The world crashes when I navigate to the link provided by the CursorPaginator. What gives? The builder doesn't change, so I'm not sure how I assign the correct parameters that are used to set the cursor or how to check the parameters are being read properly. Any better ideas?

0 likes
9 replies
Snapey's avatar

the cursorPaginate method will determine the position from the request. Do you have anything else going off with route parameters?

georgefromohio's avatar

No nothing, all I have is the limit parameter. It works fine without the orderBy

kensmithzzz's avatar

That looks pretty straightforward, and I am using a very similar query successfully with cursorPaginate in one of my projects.

I would take a look at your pagination blade file and make sure you're not doing something funny with $paginator->nextPageUrl()

Other than that, maybe try another of your Models in case "People" has some unexpected side effects from some of its settings.

georgefromohio's avatar

Oooh... :(

Do you have success with an orderBy attached? I haven't manipulated the paginator. I can't even get that far with Illuminate/Pagination/AbstractCursorPaginator.php throwing an exception

Only arrays and objects are supported when cursor paginating items.

I've tried removing custom attributes. No dice. The nextPageUrl() is rendering correctly.

Snapey's avatar

does it work with regular pagination?

georgefromohio's avatar

Yes. And I did a quick check again. Seems like everything works with regular pagination, simple pagination and cursor pagination. The only time it fails is when sorting.

The furthest I got was switching to a raw DB call:

$people = DB::connection('cms')
	->table('people')
	->orderByDesc('created_at')
	->cursorPaginate($limit);

This is the only way I could get the links to work... BUT The links are not still not behaving properly. With the limit set at 10, the pages jump 150 records at a time. I'll try a fresh install and see if something happened along the way. Any ideas as to why Eloquent doesn't work?

georgefromohio's avatar

This issue only happens when adding and orderBy with timestamp fields. Couldn't figure out a workaround so I got it working again another way. Thanks again for your inputs. Appreciate it ✌️

sukhchain's avatar

Same here, I have 3 deals in DB and i'm running this:

$deals = Deal::active()->orderBy('updated_at', 'desc')->cursorPaginate(1);

From first page it goes well to second, works when going to third page, even works when going from third to second. Then from second to first it throws error.

throw new Exception('Only arrays and objects are supported when cursor paginating items.');
georgefromohio's avatar

@sukhchain allow me to help you from my mistakes. If you are working with dummy data or data that has many timestamps with identical dates, this is a no go since most of the updated_at fields are the same and that's the only way the cursor can page the data. One way to get around this is using microseconds for timestamps OR use another numeric way of sorting.

For MySQL/MariaDB if you try -

SELECT NOW(3); #Milli OR
SELECT NOW(6); #Micro

You can check if your database supports higher resolution timestamps. That's the direction I went, might be of help?

Please or to participate in this conversation.