GraphQL pagination
This tutorial assumes that you have successfully completed the Get started with GraphQL tutorial, and that you still have the FaunaDB Console open in a browser tab/window, on the GraphQL Playground screen. If your FaunaDB Console session has expired:
|
Databases can contain a lot of data. Queries that attempt to return a large fraction of the data can strain the resources of the database server and client application. This tutorial demonstrates how to use pagination, where only a small group of results is returned for any one query and subsequent queries can fetch the next or previous group.
The steps:
-
Create the file
schema-paginate.gql
with the following content (or download it here):type Letter { letter: String! } type Query { allLetters: [Letter!] }
-
Import the new GraphQL schema into FaunaDB
Click the UPDATE SCHEMA button in the GraphQL Playground screen (in your browser), which opens your browser’s file selector. Select the
schema-paginate.gql
file, and click the file selector’s Open button.This new schema only updates collections (and associated indexes) with the same name. Any other collections are unaffected. -
Let’s create some documents. Bulk creation of documents is easiest to do using FQL.
Open a terminal and run:
fauna shell graphql
After FaunaDB Shell starts, run the following query:
Map( ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"], Lambda("X", Create(Collection("Letter"), { data: { letter: Var("X") }})) )
You should see output similar to:
[ { ref: Ref(Collection("Letter"), "234438806828235266"), ts: 1559837118920000, data: { letter: 'a' } }, { ref: Ref(Collection("Letter"), "234438806828228098"), ts: 1559837118920000, data: { letter: 'b' } }, { ref: Ref(Collection("Letter"), "234438806828241410"), ts: 1559837118920000, data: { letter: 'c' } }, { ref: Ref(Collection("Letter"), "234438806828231170"), ts: 1559837118920000, data: { letter: 'd' } }, { ref: Ref(Collection("Letter"), "234438806828237314"), ts: 1559837118920000, data: { letter: 'e' } }, { ref: Ref(Collection("Letter"), "234438806828224002"), ts: 1559837118920000, data: { letter: 'f' } }, { ref: Ref(Collection("Letter"), "234438806828242434"), ts: 1559837118920000, data: { letter: 'g' } }, { ref: Ref(Collection("Letter"), "234438806828238338"), ts: 1559837118920000, data: { letter: 'h' } }, { ref: Ref(Collection("Letter"), "234438806828233218"), ts: 1559837118920000, data: { letter: 'i' } }, { ref: Ref(Collection("Letter"), "234438806828230146"), ts: 1559837118920000, data: { letter: 'j' } }, { ref: Ref(Collection("Letter"), "234438806828243458"), ts: 1559837118920000, data: { letter: 'k' } }, { ref: Ref(Collection("Letter"), "234438806828244482"), ts: 1559837118920000, data: { letter: 'l' } }, { ref: Ref(Collection("Letter"), "234438806828240386"), ts: 1559837118920000, data: { letter: 'm' } }, { ref: Ref(Collection("Letter"), "234438806828227074"), ts: 1559837118920000, data: { letter: 'n' } }, { ref: Ref(Collection("Letter"), "234438806828226050"), ts: 1559837118920000, data: { letter: 'o' } }, { ref: Ref(Collection("Letter"), "234438806828234242"), ts: 1559837118920000, data: { letter: 'p' } }, { ref: Ref(Collection("Letter"), "234438806828245506"), ts: 1559837118920000, data: { letter: 'q' } }, { ref: Ref(Collection("Letter"), "234438806828220930"), ts: 1559837118920000, data: { letter: 'r' } }, { ref: Ref(Collection("Letter"), "234438806828221954"), ts: 1559837118920000, data: { letter: 's' } }, { ref: Ref(Collection("Letter"), "234438806828239362"), ts: 1559837118920000, data: { letter: 't' } }, { ref: Ref(Collection("Letter"), "234438806828225026"), ts: 1559837118920000, data: { letter: 'u' } }, { ref: Ref(Collection("Letter"), "234438806828232194"), ts: 1559837118920000, data: { letter: 'v' } }, { ref: Ref(Collection("Letter"), "234438806828246530"), ts: 1559837118920000, data: { letter: 'w' } }, { ref: Ref(Collection("Letter"), "234438806828236290"), ts: 1559837118920000, data: { letter: 'x' } }, { ref: Ref(Collection("Letter"), "234438806828229122"), ts: 1559837118920000, data: { letter: 'y' } }, { ref: Ref(Collection("Letter"), "234438806828222978"), ts: 1559837118920000, data: { letter: 'z' } } ]
-
Let’s verify that GraphQL Playground can see all of the letters.
Copy the following GraphQL query:
query FindAllLetters { allLetters { data { _id letter } } }
Then click the "new tab"
+
button on the GraphQL Playground screen in your browser (at the top left, just right of the last query tab). Paste the query into the left panel, and click the "Play" button. The query should execute and the response should appear in the right panel:{ "data": { "allLetters": { "data": [ { "_id": "234439110495830537", "letter": "a" }, { "_id": "234439110495831561", "letter": "f" }, { "_id": "234439110495832585", "letter": "g" }, { "_id": "234439110495833609", "letter": "i" }, { "_id": "234439110495834633", "letter": "c" }, { "_id": "234439110495835657", "letter": "l" }, { "_id": "234439110495836681", "letter": "h" }, { "_id": "234439110495837705", "letter": "d" }, { "_id": "234439110495838729", "letter": "b" }, { "_id": "234439110495839753", "letter": "j" }, { "_id": "234439110495840777", "letter": "w" }, { "_id": "234439110495841801", "letter": "m" }, { "_id": "234439110495842825", "letter": "n" }, { "_id": "234439110495843849", "letter": "o" }, { "_id": "234439110495844873", "letter": "p" }, { "_id": "234439110495845897", "letter": "s" }, { "_id": "234439110495846921", "letter": "k" }, { "_id": "234439110495847945", "letter": "e" }, { "_id": "234439110495848969", "letter": "r" }, { "_id": "234439110495849993", "letter": "y" }, { "_id": "234439110495851017", "letter": "q" }, { "_id": "234439110495852041", "letter": "x" }, { "_id": "234439110495853065", "letter": "u" }, { "_id": "234439110495854089", "letter": "v" }, { "_id": "234439110495855113", "letter": "z" }, { "_id": "234439110495856137", "letter": "t" } ] } } }
-
Query for a small group of letters
How should we query for only a small group of letters? When we defined the
allLetters
query, the GraphQL API automatically created an index for the documents in theLetter
collection. Any queries which involve lists of values automatically accept a_size
parameter, specifying the maximum number of documents to return, and a_cursor
parameter, specifying a marker that describes the position and direction within the result set.Modify the query to look like this:
query FindAllLetters { allLetters(_size: 5) { data { _id letter } } }
Then click the "Play" button. The query should execute and the response should appear in the right panel:
{ "data": { "allLetters": { "data": [ { "_id": "234439110495830537", "letter": "a" }, { "_id": "234439110495831561", "letter": "f" }, { "_id": "234439110495832585", "letter": "g" }, { "_id": "234439110495833609", "letter": "i" }, { "_id": "234439110495834633", "letter": "c" } ] } } }
By specifying
_size: 5
, we are telling GraphQL that we only want 5 records, and that’s how many we received. Had we specified 1,000 instead, we would only receive 26 documents, since that’s as many as the collection contains. If you don’t specify_size
, you get at most 50 results. -
Query for groups of letters using cursors
How would we get the next group of letters? First, we need to modify the query a little to retrieve the cursor information:
query FindSomeLetters { allLetters(_size: 5) { data { _id letter } before after } }
Then click the "Play" button. The query should execute and the response should appear in the right panel:
{ "data": { "allLetters": { "data": [ { "_id": "234439110495830537", "letter": "a" }, { "_id": "234439110495831561", "letter": "f" }, { "_id": "234439110495832585", "letter": "g" }, { "_id": "234439110495833609", "letter": "i" }, { "_id": "234439110495834633", "letter": "c" } ], "before": null, "after": "2DOB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==" } } }
By asking for
before
andafter
in the query, GraphQL includes those values in the result. These represent cursors, which are markers that define a position in the results, as well as the direction involved.The
before
cursor isnull
, which tells us that there are no groups of documents before the current results. Theafter
cursor tells us that there are more results after thec
result. Let’s see those results. Modify the query to look like this:query FindSomeLetters { allLetters(_size: 5, _cursor: "2DOB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==") { data { _id letter } before after } }
Replace
2DOB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==
with the value of theafter
cursor from the previous query’s output. Then click the "Play" button. The query should execute and the response should appear in the right panel:{ "data": { "allLetters": { "data": [ { "_id": "234439110495835657", "letter": "l" }, { "_id": "234439110495836681", "letter": "h" }, { "_id": "234439110495837705", "letter": "d" }, { "_id": "234439110495838729", "letter": "b" }, { "_id": "234439110495839753", "letter": "j" } ], "before": "2DKB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==", "after": "2DOB2DRyMjM0NDM5MTEwNDk1ODQwNzc3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==" } } }
Notice that we have a new group of letters, the
before
cursor now indicates that there are letters before this group, and because theafter
cursor is notnull
, there are more letters after this group.What happens if we change
_size
when we’re not at the start of the result set? Let’s try that! Modify the query so that_size
is now 30:query FindSomeLetters { allLetters(_size: 30, _cursor: "2DOB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==") { data { _id letter } before after } }
Replace
2DOB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==
with the value of theafter
cursor from the previous query’s output. Then click the "Play" button. The query should execute and the response should appear in the right panel:{ "data": { "allLetters": { "data": [ { "_id": "234439110495835657", "letter": "l" }, { "_id": "234439110495836681", "letter": "h" }, { "_id": "234439110495837705", "letter": "d" }, { "_id": "234439110495838729", "letter": "b" }, { "_id": "234439110495839753", "letter": "j" }, { "_id": "234439110495840777", "letter": "w" }, { "_id": "234439110495841801", "letter": "m" }, { "_id": "234439110495842825", "letter": "n" }, { "_id": "234439110495843849", "letter": "o" }, { "_id": "234439110495844873", "letter": "p" }, { "_id": "234439110495845897", "letter": "s" }, { "_id": "234439110495846921", "letter": "k" }, { "_id": "234439110495847945", "letter": "e" }, { "_id": "234439110495848969", "letter": "r" }, { "_id": "234439110495849993", "letter": "y" }, { "_id": "234439110495851017", "letter": "q" }, { "_id": "234439110495852041", "letter": "x" }, { "_id": "234439110495853065", "letter": "u" }, { "_id": "234439110495854089", "letter": "v" }, { "_id": "234439110495855113", "letter": "z" }, { "_id": "234439110495856137", "letter": "t" } ], "before": "2DKB2DRyMjM0NDM5MTEwNDk1ODM1NjU3gWdMZXR0ZXJzgWdjbGFzc2VzgICAgA==", "after": null } } }
Since we asked for 30 results, and we only had 26 altogether, and we started at the 6th result, we see all of the remaining letters in the results. The
before
cursor tells us that there are letters before this group. Since theafter
cursor isnull
, there are no letters after this group.
Conclusion
This tutorial has demonstrated how pagination works in GraphQL, shown you how to constrain the number of results, and how to issue subsequent queries to return different groups from a larger result set.
Was this article helpful?
We're sorry to hear that.
Tell us how we can improve!
documentation@fauna.com
Thank you for your feedback!