Home > front end >  Why items repeat in Prisma pagination with orderBy?
Why items repeat in Prisma pagination with orderBy?

Time:08-31

The data looks as follows:

13 users with id's 2-13. User 2 got 2 likes, user 10 got 2 likes, user 3 got 1 like. The rest didn't get any likes.

Prisma query looks like this:

return this.prisma.user.findMany({
  skip: Number(page) * Number(size),
  take: Number(size),
  orderBy: { likesReceived: { _count: "desc" } 
});

When I send a query to the database, ordering by likesReceived I get these responses:

page size items id's
0 5 2, 10, 3, 4, 14
1 5 6, 7, 8, 9, 11
2 5 12, 13, 14

User 14 appears twice, and user 5 is missing. Why?

Additional sorting by id fixes the problem:

return this.prisma.user.findMany({
  skip: Number(page) * Number(size),
  take: Number(size),
  orderBy: [{ likesReceived: { _count: "desc" } }, { id: "asc" }],
});

Results:

page size items id's
0 5 2, 10, 3, 4, 5
1 5 6, 7, 8, 9, 11
2 5 12, 13, 14

When is specifying a second parameter in orderBy with pagination necessary for it to work well?

CodePudding user response:

I had a similar issue with Laravel using sqlserver.

Laravel was doing a different query for the first page than the subsequent pages. For page 1 they used...

SELECT TOP 100 * FROM users

while for subsequent pages they used row_number(), something like...

SELECT * FROM (
    SELECT 
        ROW_NUMBER() row_num, 
        *
    FROM
        users
    ) u    
WHERE
    row_num > 100 AND row_num <=201;

Sqlserver doesn't do a default order by Default row order in SELECT query - SQL Server 2008 vs SQL 2012, rather each time it will choose the most optimized way. Therefore on the page 1 query using TOP it chose one way to order and on page 2 with row_number() it chose a different way to order. Thereby returning duplicate results in page 2 that were already in page 1. This was true even though I had many other order bys.

Mysql also seems not to have a default order by SQL: What is the default Order By of queries?.

I don't know if Prisma does the same thing with mysql. Printing out the queries may shed light on if different queries are used for different pages.

Either way if you're using pagination it may make sense, to do as you mentioned and to always use id as a final order by. Like this even if your other intended order bys allow the same record to be on multiple pages the final order by id will ensure that doesn't occur, since now you're forcing it to order by ids instead of choosing a more optimal approach that doesn't order by ids.

In your case since user 14 has 0 likes it can be on any page after 2, 10 and 3 and still satisfy your likesReceived orderBy. But with the id order by then it'll always be on page 2, since page 1 will now have 4 and 6 as the last records, instead of 14, due to the 2nd orderBy of id.

  • Related