0

How does graphql generates hasNextPage if only "first" parameter passed? I am using

return relay.connectionFromPromisedArray( global.app.get('model__user').getUsers(args), args );

and query:

query RootQueryType { viewer { user(id: 1){ id,email,friends(first: 5) {edges {cursor, node { id, email } }, pageInfo { hasNextPage } } } } }

So how can i pass to graphql / relay friends count so hasNextPage will be generated correct?

Artyom Trityak
  • 647
  • 6
  • 17

2 Answers2

1

Relay pagination is not page based, but rather cursor based. So you paginate by saying "I want X items after item Y". Item Y is not pointed to as a page number or an offset, but rather as a pointer to that exact object, a so-called cursor. This model of pagination is nice for, for example, infinite scrolling. "Pages" are also stable after adding or removing items, as they don't depend on number of items.

hasNextPage in Relay GraphQL spec just indicates whether there are more items after the last element that has been retrieved. So in your case, it means there are more than 5 elements in total and you'll get more elements if you do

friends(first: 5, after: "CURSOR_TO_THE_LAST_ELEMENT")

You can retrieve cursor from the edges list, it's one of the elements alongside node there.

freiksenet
  • 3,569
  • 3
  • 28
  • 28
1

You can find detailed information on the relay pagination algorithm here: https://facebook.github.io/relay/graphql/connections.htm#sec-Pagination-algorithm.

To answer your specific question about hasNextPage, this is the algorithm:

function hasNextPage(allEdges, before, after, first, last) {

    // If first was not set, return false.
    if (first === null) { return false; }

    // Apply the before & after cursor arguments to the set of edges.
    // i.e. edges is the set of edges between the before and after cursors
    const edges = ApplyCursorsToEdges(allEdges, before, after)

    // If more edges exist between the before & after cursors than
    // you are asking for then there is a next page.
    if (edges.length > first) { return true; }
    return false
}

A quick note on cursor vs page based pagination. It is generally a bad idea to paginate using fixed page sizes. A classic example of this is using the OFFSET keyword in SQL to grab the next page. There are many issues with this approach. For example, what would happen if a new object was inserted while you were in the middle of paginating the set? If the new object was inserted before the page you are currently grabbing and you use a fixed offset you are going to grab an object that you have already grabbed which leads to duplicate data in your presentation layer. Using cursors for pagination fixes this problem by allowing you to keep track of the objects themselves instead of counts of the objects.

Once last thing with relay pagination specifically. I recommend only using (first & after) OR (last & before) at any given time. Using both in the same query can lead to logical, yet unexpected results.

Best of luck!