Check out v4 of the Fauna CLI

v4 of the Fauna CLI is now in beta.

The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start.

Set.paginate()

Get a page of paginated results using an after cursor.

Signature

Set.paginate((cursor: String, size: Number) => { data: Array<Any>, after: String | Null })

Description

Gets a page of paginated results using an after cursor.

The default page size of 16 can be changed using the set.paginate() or set.pageSize() method, in the range 1 to 16000 (inclusive).

The cursor is stable in the sense that pagination through a Set is done for a fixed snapshot time, giving you a view of your data as it existed across the whole Set at the instant you started paginating. For example, given Set [a, b, c] when you start paginating, one item at a time, even if you delete item c after you started reading the Set, item c is returned.

The exception is if the history is no longer available for the deleted item because history_days is set to the default value of 0 or is less than the minimum valid time needed. In that case, the deleted item is not returned with the paginated results and an error is returned:
Requested timestamp <time> less than minimum allowed timestamp..

A cursor is valid for history_days plus 15 minutes.

Invalid cursor

If you pass an invalid or expired after cursor to Set.paginate(), the Fauna Core HTTP API’s Query endpoint returns a query runtime error with an invalid_cursor error code and a 400 HTTP status code:

{
  "error": {
    "code": "invalid_cursor",
    "message": "Cursor cursor is invalid or expired."
  },
  ...
}

Fauna’s client drivers include classes for query runtime errors:

Parameters

Parameter Type Required Description

cursor

String

Yes

Encoded string representing a pagination cursor, a Base64-encoded object representing the state of a Set during pagination.

size

Number

Maximum number of Set elements to return in a page.

Return value

Type Description

An object with:

Field Type Description

data

Array representing a page of results. The number of elements is limited by the size parameter.

after

Cursor for the next page of results. The cursor is valid for history_days plus 15 minutes.

If no additional pages exist, after is Null.

Examples

Basic example

  1. The page includes a pagination cursor:

    Product.all().pageSize(2) { name }
    {
      data: [
        {
          name: "cups"
        },
        {
          name: "donkey pinata"
        }
      ],
      after: "hdWC1Y..."
    }
  2. Use the cursor to access the next page:

    Set.paginate("hdWC1Y...")
    {
      data: [
        {
          name: "pizza"
        },
        {
          name: "avocados"
        }
      ],
      after: "hdWC1Y..."
    }

Paginate in reverse

Paginated queries don’t include a before cursor. Instead, you can use a range search and document IDs or other unique field values to paginate in reverse. For example:

  1. Run an initial paginated query:

    Product.all().pageSize(2)
    {
      data: [
        {
          id: "111",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "cups",
          description: "Translucent 9 Oz, 100 ct",
          price: 698,
          stock: 100,
          category: Category("123")
        },
        {
          id: "222",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "donkey pinata",
          description: "Original Classic Donkey Pinata",
          price: 2499,
          stock: 50,
          category: Category("123")
        }
      ],
      after: "hdW..."
    }
  2. Page forward until you find the document you want to start reversing from:

    Set.paginate("hdW...")

    Copy the ID of the document:

    {
      data: [
        {
          id: "333",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "pizza",
          description: "Frozen Cheese",
          price: 499,
          stock: 100,
          category: Category("456")
        },
        {
          // Begin reverse pagination from this doc ID.
          id: "444",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "avocados",
          description: "Conventional Hass, 4ct bag",
          price: 399,
          stock: 1000,
          category: Category("789")
        }
      ],
      after: "hdW..."
    }
  3. To reverse paginate, run the original query with:

    // "444" is the ID of the document to reverse from.
    Product.all({ to: "444" }).reverse().pageSize(2)
    {
      data: [
        {
          // The results of the previous query are reversed.
          id: "444",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "avocados",
          description: "Conventional Hass, 4ct bag",
          price: 399,
          stock: 1000,
          category: Category("789")
        },
        {
          id: "333",
          coll: Product,
          ts: Time("2099-08-16T14:00:59.075Z"),
          name: "pizza",
          description: "Frozen Cheese",
          price: 499,
          stock: 100,
          category: Category("456")
        }
      ],
      after: "hdW..."
    }

    To get historical snapshots of documents at the time of the original query, use an at expression:

    // Time of the original query.
    let originalQueryTime = Time.fromString("2099-08-16T14:30:00.000Z")
    at (originalQueryTime) {
      // "444" is the ID of the document to reverse from.
      Product.all({ to: "444" }).reverse().pageSize(2)
    }
  4. Repeat the previous step to continue paginating in reverse:

    Product.all({ to: "333" }).reverse().pageSize(2)

Traverse Set references

Sets are not persistable. You can’t store a Set as a field value or create a field definition that accepts a Set.

Instead, you can use a computed field to define a read-only function that dynamically fetches a Set:

collection Customer {
  ...
  // Computed field definition for the `orders` field.
  // `orders` contains a reference to a Set of `Order` collection documents.
  // The value is computed using the `Order` collection's
  // `byCustomer()` index to get the customer's orders.
  compute orders: Set<Order> = ( customer => Order.byCustomer(customer))
  ...
}

If the field isn’t projected, it contains an after pagination cursor that references the Set:

// Get a `Customer` document.
Customer.byEmail("alice.appleseed@example.com").first()
{
  id: "111",
  coll: Customer,
  ts: Time("2099-10-22T21:56:31.260Z"),
  cart: Order("412483941752112205"),
  // `orders` contains an `after` cursor that
  // references the Set of `Order` documents.
  orders: "hdW...",
  name: "Alice Appleseed",
  email: "alice.appleseed@example.com",
  address: {
    street: "87856 Mendota Court",
    city: "Washington",
    state: "DC",
    postalCode: "20220",
    country: "US"
  }
}

To materialize the Set, project the computed field:

let customer = Customer
                .where(.email == "alice.appleseed@example.com")
                .first()

// Project the `name`, `email`, and `orders` fields.
customer {
  name,
  email,
  orders
}
{
  name: "Alice Appleseed",
  email: "alice.appleseed@example.com",
  orders: {
    data: [
      {
        id: "412483941752112205",
        coll: Order,
        ts: Time("2099-10-22T21:56:31.260Z"),
        items: "hdW...",
        total: 5392,
        status: "cart",
        customer: Customer("111"),
        createdAt: Time("2099-10-22T21:56:31.104083Z"),
        payment: {}
      },
      ...
    ]
  }
}

Alternatively, you can pass the after cursor to Set.paginate():

Set.paginate("hdW...", 2)
{
  // Returns a materialized Set of `Order` documents.
  data: [
    {
      id: "412483941752112205",
      coll: Order,
      ts: Time("2099-10-22T21:56:31.260Z"),
      items: "hdW...",
      total: 5392,
      status: "cart",
      customer: Customer("111"),
      createdAt: Time("2099-10-22T21:56:31.104083Z"),
      payment: {}
    },
    ...
  ]
}

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!