Sorting and pagination
sort takes one key or an array of up to 8. Each key is _score, _doc or a field of type keyword, numeric, boolean or date:
{ "sort": [ { "price": "asc" }, { "rating": { "order": "desc", "missing": "_last" } }, { "sku": "asc" } ]}| Form | Meaning |
|---|---|
"price" |
Ascending (_score defaults to descending) |
{"price": "desc"} |
Explicit order |
{"price": {"order": "desc", "missing": "_first", "mode": "max"}} |
Long form |
missing takes _last (default) or _first; custom missing values are rejected. mode takes min or max, for fields with several values. Rejected: unmapped_type, numeric_type, format, nested, script sorts. Sorting on a text field is an error, with Elasticsearch’s message.
Each hit carries a sort array with its sort values. When _score is not among the sort keys, hits have "_score": null, as in Elasticsearch, unless you set "track_scores": true.
Make the order total
Section titled “Make the order total”Two products with the same price can come back in either order unless something breaks the tie. End every sort with a unique field; the sample catalog has sku for this. The example shop does it on every sort:
const SORT_CLAUSES: Readonly<Record<Sort, estypes.Sort>> = { relevance: [{ _score: { order: "desc" } }, { sku: { order: "asc" } }], price_asc: [{ price: { order: "asc" } }, { sku: { order: "asc" } }], price_desc: [{ price: { order: "desc" } }, { sku: { order: "asc" } }], rating: [{ rating: { order: "desc" } }, { sku: { order: "asc" } }], newest: [{ created_at: { order: "desc" } }, { sku: { order: "asc" } }],};from and size
Section titled “from and size”size is the number of hits to return (default 10) and from the number to skip (default 0). from + size may not exceed 10,000 (Elasticsearch’s index.max_result_window):
{ "error": { "root_cause": [{ "type": "illegal_argument_exception", "reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10010]. …" }], "type": "search_phase_execution_exception", "reason": "all shards failed", "phase": "query", "grouped": true, "failed_shards": [ … ] }, "status": 400}A negative from is an error; a negative size means the default, as in Elasticsearch 7.17. size: 0 returns no hits and is the usual way to ask for aggregations only.
search_after
Section titled “search_after”For deep pagination, pass the sort values of the last hit of the previous page:
{ "size": 24, "sort": [{ "price": "asc" }, { "sku": "asc" }], "search_after": [44.99, "SKU-000001"]}search_after needs an explicit sort, one value per sort key, and from must be 0.
track_total_hits
Section titled “track_total_hits”By default the total is counted exactly up to 10,000; above that, hits.total reports {"value": 10000, "relation": "gte"}. true counts exactly, false (or -1) leaves the total out, and a number sets the threshold.
_source
Section titled “_source”Controls which fields of each document are returned:
| Value | Returns |
|---|---|
true (default) |
The whole document |
false |
No _source |
"name" or ["sku", "name", "price"] |
Only these fields (patterns with * allowed) |
{"includes": [...], "excludes": [...]} |
Included minus excluded |
Returning fewer fields makes responses smaller, which matters for the per-response size limit of 8 MiB.