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)