Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Ordering and Pagination

In the Laravel-Opensearch integration, ordering and pagination are essential features that enable developers to manage and present data effectively. These features are designed to work seamlessly within the Laravel ecosystem, designed to feel native to Laravel developers familiar with Eloquent

Ordering

OpenSearch inherently ranks search results based on relevance (using internal scoring and ranking algorithms). However, it is often necessary to sort results based on specific fields. The Laravel-Opensearch integration provides a simple and intuitive way to sort search results using the orderBy and orderByDesc methods.


OrderBy

The orderBy method allows you to specify the field by which the results should be sorted and the direction of the sort (ascending or descending). This method is straightforward and aligns with the Laravel Eloquent’s orderBy functionality.

Product::orderBy('status')->get();

Find all products and order them by their status in ascending order.

{
"index": "products",
"body": {
"sort": [
{
"status": {
"order": "asc"
}
}
],
"size": 1000
}
}
Product::orderBy('created_at', 'desc')->get();

Find all products and order them by creation date in descending order.

{
"index": "products",
"body": {
"sort": [
{
"created_at": {
"order": "desc"
}
}
],
"size": 1000
}
}

If you have a field that is mapped as a text field with a keyword subfield, the package will automatically use the keyword subfield for sorting.

Product::orderBy('name')->get();

Find all products and order them by their name in ascending order via the keyword subfield.

{
"index": "products",
"body": {
"sort": [
{
"name.keyword": {
"order": "asc"
}
}
],
"size": 1000
}
}

OrderByDesc

As with Laravel’s standard eloquent, the orderByDesc method is provided to quickly sort results in descending order by a specified field, without needing to explicitly set the direction.

Product::orderByDesc('created_at')->get();

Find all products and order them by creation date in descending order.

{
"index": "products",
"body": {
"sort": [
{
"created_at": {
"order": "desc"
}
}
],
"size": 1000
}
}

Offset & Limit (skip & take)

As with Eloquent, you can use the skip and take methods in your query.

Product::skip(10)->take(5)->get();

Find all products and skip the first 10, then take the next 5.

{
"index": "products",
"body": {
"from": 10,
"size": 5
}
}

Pagination

Pagination works as expected in this Laravel-Opensearch integration.

$products = Product::where('is_active',true)
$products = $products->paginate(50)

Find all active products and paginate them with 50 products per page.

Pagination links (Blade)

{{ $products->appends(request()->query())->links() }}

Extending ordering for opensearch features

The orderBy and orderByDesc methods are designed to be Laravel native, but they can be extended to support more advanced OpenSearch features.

Full parameter scope:

  • orderBy($field, $direction = 'asc', $options = [])
  • orderByDesc($field, $options = [])

$mode

$options['mode'] = $mode;

The mode parameter allows you to specify how OpenSearch should handle sorting when multiple documents have the same value for the field being sorted. Options: min, max, sum, avg, median

Default: min when sorting in ascending order, max when sorting in descending order.

$missing

$options['missing'] = $missing;

Default: _last

The missing parameter allows you to specify how OpenSearch should handle sorting when a document is missing the field being sorted. Options: _first, _last, or a custom value.

Example with options:

$options = [
'mode' => 'avg',
'missing' => '_first'
];
// pricing_history is an array of prices ex: [9.99, 15.50, 29, 20.50]
Product::where('is_active',true)->orderBy('pricing_history', $options)->get();

Find all active products and order them by the average price in the pricing history array in descending order.

{
"index": "products",
"body": {
"query": {
"term": {
"is_active": {
"value": true
}
}
},
"sort": [
{
"pricing_history": {
"mode": "avg",
"missing": "_first",
"order": "asc"
}
}
],
"size": 1000
}
}

OrderBy Geo Distance

The orderByGeo method is a specialized method for sorting by geo distance. This sorting method only works with geo fields and can be used to sort results based on their distance from a specified point.

Parameter scope:

  • orderByGeo(string $column, array $pin, $direction = 'asc', $options = [])
  • orderByGeoDesc(string $column, array $pin, , $options = [])

$pin

The point(s) from which to calculate the distance. This can be a single point or an array of points.

  • A point is an array with two values: [lon, lat] (longitude, latitude) - Order matters and OpenSearch does not use the standard [lat, lon] format
  • For multiple points, use an array of points: [[lon1, lat1], [lon2, lat2], ...]
  • You can also specify the lat and lon keys: ['lat' => 51.50853, 'lon' => -0.12574]

$direction

  • The direction in which to sort the results. Options: asc, desc
  • asc sorts by shortest distance from the pin
  • desc sorts by longest distance from the pin

$options

$options = [
'unit' => $unit,
'mode' => $mode,
'distance_type' => $type
];
  • $unit

    • The unit to use when computing sort values. Options: m, km, mi, yd, ft
  • $mode

    • Used for when a field has several geo points. By default, the shortest distance is used when sorting in ascending order and the longest distance when sorting in descending order.
    • Options: min, max, sum, avg, median
  • $type

    • The type of distance calculation to use.
    • Options: arc, plane
    • Note: plane is faster, but inaccurate on long distances and close to the poles.
// Lat:51.50853 & Lon:-0.12574 (London)
Product::where('is_active',true)->orderByGeo('manufacturer.location', [-0.12574, 51.50853])->get();
// OR
Product::where('is_active',true)->orderByGeo('manufacturer.location', ['lat' => 51.50853, 'lon' => -0.12574])->get();

Find all active products and order them by the closest distance of the manufacturer’s location to London.

{
"index": "products",
"body": {
"query": {
"term": {
"is_active": {
"value": true
}
}
},
"sort": [
{
"_geo_distance": {
"manufacturer.location": [
-0.12574,
51.50853
],
"order": "asc"
}
}
],
"size": 1000
}
}

With options

// Lat:48.85341 & Lon:2.3488 (Paris)
// Lat:51.50853 & Lon:-0.12574 (London)
$options = [
'unit' => 'km',
'mode' => 'avg',
'distance_type' => 'plane'
];
Product::where('is_active',true)->orderByGeoDesc('manufacturer.location', [[2.3488, 48.85341], [-0.12574, 51.50853]], $options)->get();
//Or
Product::where('is_active',true)->orderByGeoDesc('manufacturer.location', [['lat' => 48.85341, 'lon' => 2.3488], ['lat' => 51.50853, 'lon' => -0.12574]], $options)->get();

Find all active products and order them by the longest average distance of the manufacturer’s location to Paris and London.

{
"index": "products",
"body": {
"query": {
"term": {
"is_active": {
"value": true
}
}
},
"sort": [
{
"_geo_distance": {
"manufacturer.location": [
[
2.3488,
48.85341
],
[
-0.12574,
51.50853
]
],
"order": "desc",
"unit": "km",
"distance_type": "plane",
"mode": "avg"
}
}
],
"size": 1000
}
}