Pagination

When dealing with large datasets, situations frequently arise in which you need to display a large query result set one chunk, or "page", at a time. This process is called pagination. The Paginate function is Fauna’s mechanism for iterating through large result sets in pages of a specified size.

For purposes of illustration, the examples on this page use a collection named Letters which contains a document for each of the 26 letters. See the indexing tutorials for the query that creates these documents.

We can use the Paginate function to retrieve documents from the Letters collection in batches of a specified size.

The following example uses the size parameter to retrieve the first 5 documents in the Letters collection:

client.query(
  q.Map(
    q.Paginate(q.Documents(q.Collection('Letters')), { size: 5 }),
    q.Lambda('x', q.Get(q.Var('x')))
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{
  after: [ Ref(Collection("Letters"), "106") ],
  data: [
    {
      ref: Ref(Collection("Letters"), "101"),
      ts: 1645055612940000,
      data: { letter: 'A', extra: 'First' }
    },
    {
      ref: Ref(Collection("Letters"), "102"),
      ts: 1645055612940000,
      data: { letter: 'B', extra: 'second' }
    },
    {
      ref: Ref(Collection("Letters"), "103"),
      ts: 1645055612940000,
      data: { letter: 'C', extra: 'third' }
    },
    {
      ref: Ref(Collection("Letters"), "104"),
      ts: 1645055612940000,
      data: { letter: 'D', extra: '4th' }
    },
    {
      ref: Ref(Collection("Letters"), "105"),
      ts: 1645055612940000,
      data: { letter: 'E', extra: 'fifth' }
    }
  ]
}
Query metrics:
  •    bytesIn:   123

  •   bytesOut:   996

  • computeOps:     1

  •    readOps:    13

  •   writeOps:     0

  •  readBytes: 1,758

  • writeBytes:     0

  •  queryTime:  10ms

  •    retries:     0

The size parameter is optional, and defaults to 64 if it is not specified. The maximum page size is 100,000.

Using cursors

In addition to the first 5 documents of the collection, there’s one more piece of information in the results: a cursor which you can use to get the next page of results, displayed above the data results. A cursor consists of an array containing the index’s values field (if any) and the Reference of a document in a particular position within the index.

The following example uses the provided cursor with the after parameter to get the next page of 5 documents:

client.query(
  q.Map(
    q.Paginate(
      q.Documents(q.Collection('Letters')),
      {
        size: 5,
        after: [ q.Ref(q.Collection('Letters'), '6') ],
      }
    ),
    q.Lambda('x', q.Get(q.Var('x')))
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{
  before: [ Ref(Collection("Letters"), "6") ],
  after: [ Ref(Collection("Letters"), "106") ],
  data: [
    {
      ref: Ref(Collection("Letters"), "101"),
      ts: 1645055612940000,
      data: { letter: 'A', extra: 'First' }
    },
    {
      ref: Ref(Collection("Letters"), "102"),
      ts: 1645055612940000,
      data: { letter: 'B', extra: 'second' }
    },
    {
      ref: Ref(Collection("Letters"), "103"),
      ts: 1645055612940000,
      data: { letter: 'C', extra: 'third' }
    },
    {
      ref: Ref(Collection("Letters"), "104"),
      ts: 1645055612940000,
      data: { letter: 'D', extra: '4th' }
    },
    {
      ref: Ref(Collection("Letters"), "105"),
      ts: 1645055612940000,
      data: { letter: 'E', extra: 'fifth' }
    }
  ]
}
Query metrics:
  •    bytesIn:   175

  •   bytesOut: 1,109

  • computeOps:     1

  •    readOps:    13

  •   writeOps:     0

  •  readBytes: 1,758

  • writeBytes:     0

  •  queryTime:  15ms

  •    retries:     0

Note that the results for the above example includes both a before and an after cursor, indicating that we’re in the middle of our result set and we can get either an earlier or a later page by using one of the provided cursors.

When you reach the end of a result set, the last page includes a before cursor but not an after cursor, indicating that there are no pages left to fetch.

The before cursor is exclusive, meaning that it returns documents up to but not including the one specified with before. after is inclusive, meaning that it returns documents including and after the one specified.

Fetching the last page

You can fetch the last page of a result set even if you don’t know how many results are in the set by setting before to null. In Fauna’s order of sorting precedence null comes last, so null is guaranteed to be at the end of any set it is in. Fetching the last page of a result set is demonstrated in the following example:

client.query(
  q.Map(
    q.Paginate(
      q.Documents(q.Collection('Letters')),
      {
        size: 5,
        before: null,
      },
    ),
    q.Lambda('x', q.Get(q.Var('x')))
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{
  before: [ Ref(Collection("Letters"), "122") ],
  after: [ null ],
  data: [
    {
      ref: Ref(Collection("Letters"), "122"),
      ts: 1645055612940000,
      data: { letter: 'V', extra: '22nd' }
    },
    {
      ref: Ref(Collection("Letters"), "123"),
      ts: 1645055612940000,
      data: { letter: 'W', extra: 'twenty-third' }
    },
    {
      ref: Ref(Collection("Letters"), "124"),
      ts: 1645055612940000,
      data: { letter: 'X', extra: 24 }
    },
    {
      ref: Ref(Collection("Letters"), "125"),
      ts: 1645055612940000,
      data: { letter: 'Y', extra: '24 + 1' }
    },
    {
      ref: Ref(Collection("Letters"), "126"),
      ts: 1645055612940000,
      data: { letter: 'Z' }
    }
  ]
}
Query metrics:
  •    bytesIn:   137

  •   bytesOut:   999

  • computeOps:     1

  •    readOps:    13

  •   writeOps:     0

  •  readBytes: 1,562

  • writeBytes:     0

  •  queryTime:  30ms

  •    retries:     0

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!