If the fieldMap()
is defined then it will only build the fields defined within.
The id
can be excluded as the value of $user->id
will correspond to $indexedUser->id
.
When mapping enums, ensure that you also cast them in the Index Model.
If a value is not found during the build process, it will be stored as null
.
:::
If your Base Model has attributes (calculated values) that you would like to have searchable, you can define them in the fieldMap()
as if they were a regular field.
For example, $field->bool('is_active')
could be derived from a custom attribute
in the Base Model:
// @property-read bool is_active
public function getIsActiveAttribute(): bool
return $this->updated_at >= Carbon::now()->modify('-30 days');
Be mindful that these values are stored in Elasticsearch at their current state during synchronisation.
The stand-out feature of ElasticLens is the ability to embed relationships within your Index Model. This allows you to create a more structured and searchable index beyond the flat structure of your Base Model.
As an illustration, consider the following relationships around the User
model which will be the base model for our IndexedUser
model.

EX: User
has many Profiles
use PDPhilip\ElasticLens\Builder\IndexBuilder;
use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel
protected $baseModel = User::class;
public function fieldMap(): IndexBuilder
return IndexBuilder::map(User::class, function (IndexField $field) {
$field->text('first_name');
$field->text('last_name');
$field->bool('is_active');
$field->type('type', UserType::class);
$field->type('state', UserState::class);
$field->text('created_at');
$field->text('updated_at');
$field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) {
$field->text('profile_name');
$field->array('profile_tags');
EX: Profile
has one ProfileStatus
use PDPhilip\ElasticLens\Builder\IndexBuilder;
use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel
protected $baseModel = User::class;
public function fieldMap(): IndexBuilder
return IndexBuilder::map(User::class, function (IndexField $field) {
$field->text('first_name');
$field->text('last_name');
$field->bool('is_active');
$field->type('type', UserType::class);
$field->type('state', UserState::class);
$field->text('created_at');
$field->text('updated_at');
$field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) {
$field->text('profile_name');
$field->array('profile_tags');
$field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) {
EX: User
belongs to an Account
use PDPhilip\ElasticLens\Builder\IndexBuilder;
use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel
protected $baseModel = User::class;
public function fieldMap(): IndexBuilder
return IndexBuilder::map(User::class, function (IndexField $field) {
$field->text('first_name');
$field->text('last_name');
$field->bool('is_active');
$field->type('type', UserType::class);
$field->type('state', UserState::class);
$field->text('created_at');
$field->text('updated_at');
$field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) {
$field->text('profile_name');
$field->array('profile_tags');
$field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) {
$field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) {
EX: User
belongs to a Country
and you don’t need to observe the Country
model to trigger a rebuild of the User
model.
use PDPhilip\ElasticLens\Builder\IndexBuilder;
use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel
protected $baseModel = User::class;
public function fieldMap(): IndexBuilder
return IndexBuilder::map(User::class, function (IndexField $field) {
$field->text('first_name');
$field->text('last_name');
$field->bool('is_active');
$field->type('type', UserType::class);
$field->type('state', UserState::class);
$field->text('created_at');
$field->text('updated_at');
$field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) {
$field->text('profile_name');
$field->array('profile_tags');
$field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) {
$field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) {
$field->embedsBelongTo('country', Country::class)->embedMap(function (IndexField $field) {
$field->text('country_code');
$field->text('currency');
})->dontObserve(); // Don't observe changes in the country model
EX: User
has Many UserLogs
and you only want to embed the last 10:
use PDPhilip\ElasticLens\Builder\IndexBuilder;
use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel
protected $baseModel = User::class;
public function fieldMap(): IndexBuilder
return IndexBuilder::map(User::class, function (IndexField $field) {
$field->text('first_name');
$field->text('last_name');
$field->bool('is_active');
$field->type('type', UserType::class);
$field->type('state', UserState::class);
$field->text('created_at');
$field->text('updated_at');
$field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) {
$field->text('profile_name');
$field->array('profile_tags');
$field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) {
$field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) {
$field->embedsBelongTo('country', Country::class)->embedMap(function (IndexField $field) {
$field->text('country_code');
$field->text('currency');
})->dontObserve(); // Don't observe changes in the country model
$field->embedsMany('logs', UserLog::class, null, null, function ($query) {
$query->orderBy('created_at', 'desc')->limit(10); // Limit the logs to the 10 most recent
})->embedMap(function (IndexField $field) {
$field->array('log_data');
text($field)
integer($field)
array($field)
bool($field)
type($field, $type)
- Set own type (like Enums)embedsMany($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)
embedsBelongTo($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)
embedsOne($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)