Pagination Using pagination and slicing to work with search queries
Use Pagination to query a list of data in discrete parts. Also, use the cursor-based pagination to select which set of results to retrieve from a connection.
Implementing pagination in data-heavy queries helps to:
Optimize the application performance
Reduce the load time the application is rendering the results in the UI.
Use Slicing to fetch exactly the number of results from the data.
Learn more about Cursors here: https://relay.dev/graphql/connections.htm
Within pagination, connections retrieve a list of nodes . A node is an object that has a global ID. Nodes are said to be connected by edges .
node
: Used to select the fields that you want to retrieve from the node at each edge.
edges
: Used to select the fields that you want to retrieve from each edge in the connection. The edges
field is similar to a for-loop because it retrieves the selected fields from each edge in the connection.
Example
Copy query {
edges
{
node
{
name
}
}
}
The following example retrieves the list of restaurants:
Query Response
Copy {
restaurantSearch(
query: "Mexican Restaurant" )
{
edges
{
node
{
name
}
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "The Islander Restaurant"
}
},
{
"node" : {
"name" : "Hua Ting Restaurant"
}
},
{
"node" : {
"name" : "Tom's Restaurant"
}
]
}
}
}
A cursor is a unique string that identifies a particular row. You can include the following fields in your queries to paginate your results:
pageInfo:
Each connection can return a PageInfo
object which contains general information about the particular page returned. This object includes:
hasNextPage:
displays whether there are results in the connection after the current segment.
hasPreviousPage
displays whether there are results in the connection before the current segment.
startCursor
and endCursor:
return non-null opaque strings. Both must be the cursors corresponding to the first and last nodes in edges
, respectively.
cursor:
A marker for an edge's position in the connection.
To enable forward pagination arguments, use the following fields:
first:
it takes a non-negative integer.
after:
It takes the cursor type and retrieves results after that position.
Pass the cursor
of the last edge on the previous page for after
.
last:
it takes a non-negative integer.
before:
It takes the cursor type and retrieves the results before that position.
Pass the cursor
of the first edge on the next page for before
.
Examples
Fetching results using Cursor based pagination
In the following example, use pageInfo
and cursor
fields in the queries to paginate the results.
Query Response
Copy {
restaurantSearch(
query: "Mexican Restaurant"
distance: 100
meals: "meat"
isOpen: true
first: 3
)
{
edges
{
node{
name
cityTown
country
recommendation
}
cursor
}
pageInfo{
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "The Islander Restaurant" ,
"cityTown" : "Mercer Island" ,
"country" : "US" ,
"recommendation" : "Prime Rib"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
{
"node" : {
"name" : "Hua Ting Restaurant" ,
"cityTown" : "Hinsdale" ,
"country" : "US" ,
"recommendation" : "Young Chow Noodles"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjE="
},
{
"node" : {
"name" : "Tom's Restaurant" ,
"cityTown" : "Rochester" ,
"country" : "US" ,
"recommendation" : "Fried Combo Seafood"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjI="
}
],
"pageInfo" : {
"hasNextPage" : true,
"hasPreviousPage" : false,
"startCursor" : "YXJyYXljb25uZWN0aW9uOjA=" ,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjI="
}
}
}
}
The result retrieves three results from the beginning of the connection, and they include a cursor for each edge. In addition, we asked for hasNextPage
; that will tell us if there are more edges available, or if we’ve reached the end of this connection.
Fetching results using after
parameter
In the following example, use after argument to pass the information of a specific cursor, so results display the information after that cursor. For instance, define the after
parameter with the YXJyYXljb25uZWN0aW9uOjI=
value, which corresponds to the "name": "Tom's Restaurant"
last result retrieved in the previous example:
Query Response
Copy {
restaurantSearch(
query: "Mexican Restaurant"
distance: 100
meals: "meat"
isOpen: true
first: 3
after: "YXJyYXljb25uZWN0aW9uOjI="
)
{
edges
{
node{
name
cityTown
country
recommendation
}
cursor
}
pageInfo{
hasNextPage
hasPreviousPage
startCursor
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "Queen's Pizza & Restaurant" ,
"cityTown" : "Clearwater" ,
"country" : "US" ,
"recommendation" : "Vegetarian Delight Pizza"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjM="
},
{
"node" : {
"name" : "Coco Palm Restaurant" ,
"cityTown" : "Pomona" ,
"country" : "US" ,
"recommendation" : "Ropa Vieja"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjQ="
},
{
"node" : {
"name" : "Snook's Bayside Restaurant & Grand Tiki bar" ,
"cityTown" : "Key Largo" ,
"country" : "US" ,
"recommendation" : "Conch Steak"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjU="
}
],
"pageInfo" : {
"hasNextPage" : true,
"hasPreviousPage" : false,
"startCursor" : "YXJyYXljb25uZWN0aW9uOjM=" ,
}
}
}
}
The results retrieve the next three restaurants listed immediately after the "Tom's Restaurant"
which has been retrieved in a previous example.
Query Response
Copy {
recipeSearch(
meals: [ "Breakfast" ],
query: "coconut" ,
first: 3 ,
after: "YXJyYXljb25uZWN0aW9uOjEw"
) {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
Copy {
"data" : {
"recipeSearch" : {
"edges" : [
{
"node" : {
"id" : "UmVjaXBlOjg5ZmU4Y2JhLWNlNmUtNDM5Zi04NDEzLThkZDI2NmNmZDkyZg==" ,
"name" : "Coconut Cupcakes"
} ,
"cursor" : "YXJyYXljb25uZWN0aW9uOjEx"
} ,
{
"node" : {
"id" : "UmVjaXBlOjk5YzBhYThmLTNhOWYtNGY5Mi1hZWQzLWUyZDI0ZDhhOGY2YQ==" ,
"name" : "Coconut Cupcakes"
} ,
"cursor" : "YXJyYXljb25uZWN0aW9uOjEy"
} ,
{
"node" : {
"id" : "UmVjaXBlOjEyYjQ4MGE0LThjZmYtNDJkNy1hYjQ4LTU4Mjc4NmZmZTA3MQ==" ,
"name" : "Coconut Cookies"
} ,
"cursor" : "YXJyYXljb25uZWN0aW9uOjEz"
}
] ,
"pageInfo" : {
"endCursor" : "YXJyYXljb25uZWN0aW9uOjEz" ,
"hasNextPage" : true
}
}
}
}
We can continue the pagination using the endCursor
Query Result
Copy {
restaurantSearch(
query: "Mexican Restaurant"
distance: 100
meals: "meat"
isOpen: true
first: 3
after: "YXJyYXljb25uZWN0aW9uOjI="
)
{
edges
{
node{
name
cityTown
country
recommendation
}
cursor
}
pageInfo{
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "Queen's Pizza & Restaurant" ,
"cityTown" : "Clearwater" ,
"country" : "US" ,
"recommendation" : "Vegetarian Delight Pizza"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjM="
},
{
"node" : {
"name" : "Coco Palm Restaurant" ,
"cityTown" : "Pomona" ,
"country" : "US" ,
"recommendation" : "Ropa Vieja"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjQ="
},
{
"node" : {
"name" : "Snook's Bayside Restaurant & Grand Tiki bar" ,
"cityTown" : "Key Largo" ,
"country" : "US" ,
"recommendation" : "Conch Steak"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjU="
}
],
"pageInfo" : {
"hasNextPage" : true,
"hasPreviousPage" : false,
"startCursor" : "YXJyYXljb25uZWN0aW9uOjM=" ,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjU="
}
}
}
}
Fetching results using first
parameter
The following example uses the first and after aruments to modify the edges returned by the connection, returning edges after the after
cursor, and returning the 3 first
edges.
Query Result
Copy {
restaurantSearch(
query: "Mexican Restaurant"
first: 3
after: "YXJyYXljb25uZWN0aW9uOjI="
)
{
edges
{
node{
name
cityTown
country
}
cursor
}
pageInfo{
hasNextPage
hasPreviousPage
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "Queen's Pizza & Restaurant" ,
"cityTown" : "Clearwater" ,
"country" : "US"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjM="
},
{
"node" : {
"name" : "Coco Palm Restaurant" ,
"cityTown" : "Pomona" ,
"country" : "US"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjQ="
},
{
"node" : {
"name" : "Snook's Bayside Restaurant & Grand Tiki bar" ,
"cityTown" : "Key Largo" ,
"country" : "US"
},
"cursor" : "YXJyYXljb25uZWN0aW9uOjU="
}
],
"pageInfo" : {
"hasNextPage" : true ,
"hasPreviousPage" : false
}
}
}
}
Slicing
In the following example, we retrieve the first
10 results from a recipe search containing the meal_tag Breakfast and including the term coconut.
Query Response
Copy {
restaurantSearch(
query: "Mexican Restaurant"
meals: "meat"
isOpen: true
first: 10
)
{
edges
{
node{
name
cityTown
country
recommendation
}
}
}
}
Copy {
"data" : {
"restaurantSearch" : {
"edges" : [
{
"node" : {
"name" : "The Islander Restaurant" ,
"cityTown" : "Mercer Island" ,
"country" : "US" ,
"recommendation" : "Prime Rib"
}
} ,
{
"node" : {
"name" : "Hua Ting Restaurant" ,
"cityTown" : "Hinsdale" ,
"country" : "US" ,
"recommendation" : "Young Chow Noodles"
}
} ,
{
"node" : {
"name" : "Tom's Restaurant" ,
"cityTown" : "Rochester" ,
"country" : "US" ,
"recommendation" : "Fried Combo Seafood"
}
} ,
{
"node" : {
"name" : "Queen's Pizza & Restaurant" ,
"cityTown" : "Clearwater" ,
"country" : "US" ,
"recommendation" : "Vegetarian Delight Pizza"
}
} ,
{
"node" : {
"name" : "Coco Palm Restaurant" ,
"cityTown" : "Pomona" ,
"country" : "US" ,
"recommendation" : "Ropa Vieja"
}
} ,
{
"node" : {
"name" : "Snook's Bayside Restaurant & Grand Tiki bar" ,
"cityTown" : "Key Largo" ,
"country" : "US" ,
"recommendation" : "Conch Steak"
}
} ,
{
"node" : {
"name" : "Topclass Jamaican Restaurant" ,
"cityTown" : "Orlando" ,
"country" : "US" ,
"recommendation" : "Curry Chicken"
}
} ,
{
"node" : {
"name" : "Lulu's Restaurant" ,
"cityTown" : "Van Nuys" ,
"country" : "US" ,
"recommendation" : "Greek Salad"
}
} ,
{
"node" : {
"name" : "Romas Pizzeria & Restaurant" ,
"cityTown" : "Southgate" ,
"country" : "US" ,
"recommendation" : "Ravioli (Meat or Cheese)"
}
} ,
{
"node" : {
"name" : "Subway Restaurants" ,
"cityTown" : "Overland Park" ,
"country" : "US" ,
"recommendation" : null
}
}
]
}
}
}
Last updated 10 months ago