Skip to content

Extending the Base model

In this section, we’ll dive into how to hook your Laravel models into Elasticsearch by extending the base model, allowing you to work with Elasticsearch indices as if they were regular Eloquent models.

Extending Your Model

Every model you want to index in Elasticsearch should extend the PDPhilip\Elasticsearch\Eloquent\Model. This base model extends Laravel’s Eloquent model, so you can use it just like you would any other Eloquent model.

app/Models/Product.php
namespace App\Models;
use PDPhilip\Elasticsearch\Eloquent\Model;
class Product extends Model
{
protected $connection = 'elasticsearch';
}

Just like a regular model, the index name will be inferred from the name of the model. In this example, the corresponding index for the Product model is products. In most cases, the elasticsearch connection won’t be the default connection, and you’ll need to include protected $connection = 'elasticsearch' in your model.


Model IDs

id alias for _id

$model->id and is an alias for Elasticsearch’s _id field. This is to maintain consistency with Laravel’s Eloquent ORM.

You can use either $model->id or $model->_id to access the ID of the model, but it’s recommended to use $model->id for consistency with Laravel’s Eloquent ORM.

$model = MyModel::where('id','123')->first();
echo $model->id; // 123
echo $model->_id; // 123

Laravel vs Elasticsearch generated IDs

By default, Elasticsearch will generate a unique ID for each document. However, this requires an additional API call to retrieve the ID after the document is created.

To avoid this, you can generate the ID on the Laravel side by using:

1. GeneratesUuids trait

This trait will generate a time-based UUID for the ID field when creating a new model instance.

use PDPhilip\Elasticsearch\Eloquent\Model;
use PDPhilip\Elasticsearch\Eloquent\GeneratesUuids;
class Product extends Model
{
use GeneratesUuids;
protected $connection = 'elasticsearch';

Example id:

{
"id": "OWU3ZTllNDEtNmFmNS00MjdkLWE5MmEtNmJhMTBkZWI0Y2Vh"
}
2. GeneratesElasticIds trait

This trait will generate an imitation of an Elasticsearch ID for the ID field when creating a new model instance.

use PDPhilip\Elasticsearch\Eloquent\Model;
use PDPhilip\Elasticsearch\Eloquent\GeneratesElasticIds;
class Product extends Model
{
use GeneratesElasticIds;
protected $connection = 'elasticsearch';

Example id:

{
"id": "GXUGv5UBt-dmV3b48pjF"
}

Model properties

$table

To change the inferred index name, pass in the $table property:

app/Models/Product.php
namespace App\Models;
use PDPhilip\Elasticsearch\Eloquent\Model;
class Product extends Model
{
protected $connection = 'elasticsearch';
protected $table = 'my_products';
}

Timestamps

By default, the base model will automatically set the created_at and updated_at fields. As is the case with Eloquent, you can disable this by setting the CREATED_AT and UPDATED_AT constants to null in your model

app/Models/Product.php
namespace App\Models;
use PDPhilip\Elasticsearch\Eloquent\Model;
class Product extends Model
{
protected $connection = 'elasticsearch';
const CREATED_AT = null;
const UPDATED_AT = null;
}

Limits

If your query does not include a limit, (->take(200)) then Elasticsearch will default to 10.

This tends to be impractical in a Laravel context with hybrid data, thus this integration overrides that value and defaults to 1000.

You can change this default limit by:

  1. Setting the protected $defaultLimit property in your model which will apply to that model only.
use PDPhilip\Elasticsearch\Eloquent\Model;
class Product extends Model
{
protected $defaultLimit = 10000;
protected $connection = 'elasticsearch';
}
  1. Setting the ES_OPT_DEFAULT_LIMIT environment variable in your .env file which will apply to all models that do not have a $defaultLimit property set.
ES_OPT_DEFAULT_LIMIT=10000

Query Field Map

Elasticsearch requires specific field types for certain operations such as aggregation, sorting, or filtering. For example, while a text field cannot be used directly for sorting or term-based filtering, a corresponding keyword subfield is typically employed. However, this isn’t restricted to just keywords; other field types may also need specific mappings depending on the operation.

To automate the process of using the correct field type at runtime, this package performs a mapping call unless the bypass_map_validation connection option is set to true. Enabling this setting avoids the overhead of an additional API call to fetch mappings for each query, which could affect performance. To facilitate efficient query processing without extra API calls, the model includes a $queryFieldMap property. This is an associative array where the keys are the column names and the values are the specific fields required for operations, ensuring the correct mappings are utilized.

namespace App\Models;
use PDPhilip\Elasticsearch\Eloquent\Model;
class Product extends Model
{
protected $connection = 'elasticsearch';
protected $queryFieldMap = [
'name' => 'name.keyword', // Example of a keyword subfield
'date' => 'date.long' // Hypothetical example for date fields requiring long type
];
}

This modification ensures all necessary operations are efficiently managed by leveraging the correct field mappings, enhancing performance and capability of the Elasticsearch integration in your Laravel application.


Mutators & Casting

You can use mutators and casting in your models just like you would with any other Eloquent model.

In the context of the Laravel-Elasticsearch integration, the foundational BaseModel inherits all the features of Laravel’s Eloquent model, including mutators and casting. You can use mutators and casts exactly like any standard Eloquent model.

For a comprehensive understanding of how to implement and use attribute mutators and casts within your models, refer to the official Laravel documentation on Eloquent Mutators & Casting: Laravel - Eloquent: Mutators & Casting.


Elastic Collections

Once a query is executed, the query meta is stored in the model instance as an ElasticCollection.

An ElasticCollection is a collection of an Elasticsearch record; akin to Laravel’s Eloquent\Collection and augmented with Meta Data.

You can access the query meta by calling the getMeta() method on the model instance.

$product = Product::where('color', 'green')->first();
return $product->getMeta()->toArray();
// or $product->getMetaAsArray();

returns:

{
"score": 1,
"index": "es11_products",
"table_prefix": "es11_",
"table": "products",
"table_suffix": "",
"doc_count": null,
"sort": [],
"cursor": [],
"highlights": []
}