All Products
Search
Document Center

Tablestore:Sorting and paging

Last Updated:Apr 29, 2026

When querying data with a search index, you can apply a predefined sort order or specify one at query time. To navigate large result sets, use limit/offset for offset-based paging, or use tokens for cursor-based paging.

Scenarios

Category

Method

Feature

Scenario

Sorting

Predefine a sorting method when you create a search index

Index presorting (IndexSort)

By default, results are returned in the order defined by the IndexSort parameter set during index creation.

Specify a sorting method when you query data

Sorting based on the BM25-based keyword relevance score (ScoreSort)

Sort results by BM25 relevance score. Best suited for full-text search.

Sorting based on the primary key value (PrimaryKeySort)

Sort results by primary key value. Useful when you need results ordered by unique row identifiers.

Sorting based on the values of one or more columns (FieldSort)

Sort results by one or more column values, such as sales volume or page views. Commonly used in e-commerce, social networking, and media asset management.

Sorting by geographical location (GeoDistanceSort)

Sort results by distance from a central point. Commonly used in mapping and logistics—for example, sorting nearby restaurants by distance.

Paging

Specify a paging method when you query data

Paging based on the limit and offset parameters

Jump to any page when the result set contains fewer than 100,000 rows.

Paging based on tokens

Page through results sequentially using a cursor; you can only page forward. Tokens remain valid for the duration of the query, so you can cache a previous token to return to an earlier page.

Index presorting

By default, data in a search index is sorted based on the presorting settings that are specified by the IndexSort parameter. When you use a search index to query data, the presorting settings that are specified by the IndexSort parameter determine the default order in which the matched data is returned.

When you create a search index, you can specify presorting settings by configuring the IndexSort parameter. If you do not specify presorting settings, data in the search index is sorted by primary key value.

Important
  • You can specify PrimaryKeySort or FieldSort as the presorting method for a search index. PrimaryKeySort sorts data by primary key value and FieldSort sorts data by field value.

  • Search indexes that contain Nested fields do not support index presorting.

  • If you want to modify the settings of the IndexSort parameter for an existing search index, you can dynamically modify the schema of the search index. For more information, see Dynamically modify a schema.

Specify a sorting method

Sorting requires enableSortAndAgg to be set to true on the fields you want to sort by.

You can specify a sorting method for each query. Search index-based queries support the following sorting methods. You can also specify multiple sorting methods based on different priorities.

ScoreSort

You can use ScoreSort to sort query results based on the BM25-based keyword relevance score. ScoreSort is suitable for scenarios such as full-text search.

Important
  • Before you sort the matched data by keyword relevance score, you must configure the parameters for ScoreSort. Otherwise, the matched data is sorted based on the presorting settings that are specified by the IndexSort parameter.

  • When you use ScoreSort, the field of the FuzzyKeyword type is not used for sorting and the settings of the weight parameter do not take effect for the field.

Use ScoreSort to rank results by BM25 relevance score, in ascending or descending order.

sort: {
    sorters: [
        {
            scoreSort: {
                order: TableStore.SortOrder.SORT_ORDER_ASC
            }
        }
    ]
}

PrimaryKeySort

You can use PrimaryKeySort to sort query results based on the primary key value.

Use PrimaryKeySort to order results by primary key value.

sort: {
    sorters: [
        {
            primaryKeySort: {
                order: TableStore.SortOrder.SORT_ORDER_DESC // Sort in descending order.
                //order: TableStore.SortOrder.SORT_ORDER_ASC // Sort in ascending order.
            }
        }
    ]
}

FieldSort

Use FieldSort to sort results by one or more column values.

Sort by a single column

sort: {
    sorters: [
        {
            fieldSort: {
                fieldName: "Col_Keyword",
                order: TableStore.SortOrder.SORT_ORDER_DESC
            }
        }
    ]
}

Sort by multiple columns

Specify multiple sorters to sort by a primary column first, then break ties using a secondary column.

sort: {
    sorters: [
        {
            fieldSort: {
                fieldName: "Col_Keyword",
                order: TableStore.SortOrder.SORT_ORDER_DESC
            }
        },
        {
            fieldSort: {
                fieldName: "Col_Long",
                order: TableStore.SortOrder.SORT_ORDER_DESC
            }
        }
    ]
}

GeoDistanceSort

You can use GeoDistanceSort to sort query results by geographical location.

Use GeoDistanceSort to rank results by distance from a central geographic point.

sort: {
    sorters: [
        {
            geoDistanceSort: {
                fieldName: "Col_Geo_Point",
                points: ["0,0"],// Specify the coordinate pair of the central point.
                order: TableStore.SortOrder.SORT_ORDER_ASC // Return results in ascending order of distance.
            }
        }
    ]
}

For a complete example, see Search on GitHub.

Specify a paging method

You can configure the limit and offset parameters or use tokens to page the rows in the response.

Configure the limit and offset parameters

If the total number of rows in the response is less than 100,000, you can configure the limit and offset parameters to page the rows. The sum of the values of the limit and offset parameters cannot exceed 100,000. The maximum value of the limit parameter is 100.

Note

For information about how to increase the maximum value of the limit parameter, see How do I increase the value of the limit parameter to 1000 when I call the Search operation of the search index feature to query data?

If you do not specify values for the limit and offset parameters, the default values are used. The default value of the limit parameter is 10. The default value of the offset parameter is 0.

Use offset and limit to jump directly to any page. This method supports result sets of up to 100,000 rows.

/**
 * Set offset to 90 and limit to 10 to retrieve rows 90–99.
 */
client.search({
    tableName: TABLE_NAME,
    indexName: INDEX_NAME,
    searchQuery: {
        offset: 90,
        limit: 10,
        query: {
            queryType: TableStore.QueryType.MATCH_ALL_QUERY
        },
        getTotalCount: true // Return the total number of matching rows. Default: false.
    },
    columnToGet: {
        // RETURN_ALL: return all columns.
        // RETURN_SPECIFIED: return specified columns.
        // RETURN_NONE: return primary key columns only.
        returnType: TableStore.ColumnReturnType.RETURN_ALL
    }
}, function (err, data) {
    if (err) {
        console.log('error:', err);
        return;
    }
    console.log('success:', JSON.stringify(data, null, 2));
});

Use a token

We recommend that you use a token for deep paging because this method has no limits on the paging depth.

If Tablestore cannot read all data that meets the query conditions, Tablestore returns nextToken. You can use nextToken to continue reading the subsequent data.

By default, you can only page backward when you use a token. However, you can cache and use the previous token to page forward because a token is valid during the query.

Token-based paging returns results page by page using a cursor (NextToken). Each response includes a token for the next page. Tokens are valid for the duration of the query, so cache a previous token to navigate back to an earlier page.

Important

To persist or pass NextToken to a frontend page, encode it as a Base64 string. Tokens are binary data (byte stream), not strings—using string(NextToken) loses data. Convert using Buffer:

  1. Encode: data.nextToken.toString("base64")

  2. Decode: Buffer.from(base64String, "base64")

When you use a token, the sorting method is the same as the method that is used in the previous request. Tablestore sorts data based on the IndexSort parameter by default or based on the method that you specified. You cannot specify the sorting method when you use a token. You cannot configure the offset parameter when you use a token. Data is returned page by page in sequence. This results in a slow query.

Important

Search indexes that contain Nested fields do not support IndexSort. If you require paging and you use a search index that contains Nested fields to query data, you must specify the sorting method in the query conditions to return data in the specified order. Otherwise, Tablestore does not return nextToken when only part of the data that meets the query conditions is returned.

The following examples show token-based paging in both synchronous and asynchronous modes. Both use the same initial params object.

var params = {
    tableName: TABLE_NAME,
    indexName: INDEX_NAME,
    searchQuery: {
        offset: 0,
        limit: 10,
        token: null, // Set to nextToken from the previous response to fetch the next page.
        query: {
            queryType: TableStore.QueryType.MATCH_ALL_QUERY
        },
        getTotalCount: true
    },
    columnToGet: {
        returnType: TableStore.ColumnReturnType.RETURN_SPECIFIED,
        returnNames: ["pic_tag", "pic_description", "time_stemp", "pos"]
    }
};

/**
 * Synchronous mode: await each page before fetching the next.
 */
(async () => {
  try {
    var data = await client.search(params);
    console.log('success:', JSON.stringify(data, null, 2));

    while (data.nextToken && data.nextToken.length) {
      // Encode the binary token as Base64 for storage or transfer,
      // then decode it back to binary before passing it as the next token.
      var nextToken = data.nextToken.toString("base64");
      var token = Buffer.from(nextToken, "base64");

      params.searchQuery.token = token;
      data = await client.search(params);
      console.log('token success:', JSON.stringify(data, null, 2));
    }
  } catch (error) {
      console.log(error);
  }
})()

/**
 * Asynchronous mode: use callbacks to fetch the next page.
 */
client.search(params, function (err, data) {
    console.log('success:', JSON.stringify(data, null, 2));

    if (data.nextToken && data.nextToken.length) {
        // Encode and decode the token the same way as in synchronous mode.
        var nextToken = data.nextToken.toString("base64");
        var token = Buffer.from(nextToken, "base64");

        params.searchQuery.token = token;
        client.search(params, function (err, data) {
            console.log('token success:', JSON.stringify(data, null, 2));
        });
    }
});