Skip to content

Saving Models

Saving models in the Laravel-Elasticsearch integration follows the conventional Laravel Eloquent patterns, making it easy for developers to transition or work with Elasticsearch alongside relational databases

Save a new model

Option A: Attribute Assigning

You can create a new model instance, set its attributes individually, and then save it to the Elasticsearch index. This approach is straightforward and mirrors the typical Laravel ORM usage.

$log = new UserLog;
$log->user_id = $userId;
$log->title = $title;
$log->status = 1;
$log->save();

Option B: Mass Assignment via create()

The create() method allows for mass assignment of model attributes using an associative array. This is a concise and efficient way to create and save a new model instance in one step.

$log = UserLog::create([
'user_id' => $userId,
'title' => $title,
'status' => 1,
]);

Updating a model

Updating models in Elasticsearch is consistent with Eloquent’s approach, where you fetch a model, change the attributes, and then call save().

$log = UserLog::where('status', 1)->first();
$log->status = 2;
$log->save();

For mass updates, you can use the update() method on a query builder instance, which allows updating multiple documents matching the query criteria in one operation.

$updates = Product::where('status', 1)->update(['status' => 4]);
// $updates will hold the number of documents updated

Fast Saves

Elasticsearch operates with a near real-time index, which means there’s a slight delay between indexing a document and when it becomes searchable. By default, this package saves a document and waits for the index to refresh, ensuring the document is immediately available and up to date. However, this can introduce latency in write-heavy applications.

To optimize performance, you can use saveWithoutRefresh() or createWithoutRefresh(), which skips the wait for index refresh. This is beneficial when immediate document retrieval is not necessary.

$log->saveWithoutRefresh();

and

UserLog::createWithoutRefresh($attributes);

Caution: Using saveWithoutRefresh and updating the model immediately after can lead to unexpected outcomes, such as duplicate documents.

// This pattern should be avoided:
$log = new UserLog;
$log->user_id = $userId;
$log->title = $title;
$log->status = 1;
$log->saveWithoutRefresh();
$log->company_id = 'ABC-123';
$log->saveWithoutRefresh(); // May result in two separate documents

Inserting models

Inserting models in Elasticsearch is consistent with Eloquent’s approach, where you pass in an array of arrays representing each ‘doc’ you would like created.

insert($values, $returnData = null);

UserLog::insert([
['user_id' => 'John_Doe','title' => 'First Log'],
['user_id' => 'Jane_Doe','title' => 'Second Log'],
]);

If the $returnData parameter is null or false, it will return a summary as an array:

{
"success": true,
"timed_out": false,
"took": 7725,
"total": 100000,
"created": 100000,
"modified": 0,
"failed": 0
}

Otherwise, it will return an ElasticCollection of all the inserted records.

To optimize performance, you can use insertWithoutRefresh() which skips the wait for index refresh.

insertWithoutRefresh($values, $returnData = null);

UserLog::insertWithoutRefresh([
['user_id' => 'John_Doe','title' => 'First Log'],
['user_id' => 'Jane_Doe','title' => 'Second Log'],
]);

By default, the insert method will create 1,000 row chunks that it will insert. If you would like to increase this limit update the insert_chunk_size under the connections options to whatever size you prefer.

Performance and Usage

  1. insert($values, $returnData = null)

    • Performs a bulk insert and waits for the index to refresh.
    • Ensures that inserted documents are immediately available for search.
    • Use this when you need the inserted data to be searchable right away.
    • Slower than insertWithoutRefresh but provides immediate consistency.
  2. insertWithoutRefresh($values, $returnData = null)

    • Executes bulk inserts without waiting for the index to refresh.
    • Offers a significant speed boost compared to insert().
    • The speed increase is due to skipping the index refresh operation, which can be resource-intensive.
    • Inserted records may not be immediately available for search
    • Use this when you need to insert large amounts of data quickly and can tolerate a slight delay in searchability.

When to use each

  1. Use insert() when:

    • You need immediate searchability of inserted data.
    • You’re inserting smaller batches of data where the performance difference is negligible.
    • In user-facing applications where real-time data availability is crucial.
  2. Use insertWithoutRefresh() when:

    • You’re performing large batch imports where speed is a priority.
    • In background jobs or data migration scripts where immediate searchability isn’t necessary.
    • You can handle a delay between insertion and searchability in your application logic.

First Or Create

The firstOrCreate() method retrieves the first model matching the given attributes or creates a new model if no match is found. It takes two arguments:

  • $attributes: An associative array of attributes to search for or create with.
  • $values: An associative array of values to set on the model if it is created.

Use with caution

  • This method will take the $attributes array and make a “best guess” as to how to build a query from that. String values will be treated as exact matches (Required to be a keyword) and everything else a normal where clause.
  • Don’t overload the $attributes array with too many values, use it for searching unique values, then fill the $values array with the rest of the values.
$book = Book::firstOrCreate(
['title' => $title,'author' => $author], //$attributes
['description' => $description, 'stock' => 0] //values
);

First Or Create Without Refresh

Added to the family of saving without refresh methods, firstOrCreateWithoutRefresh() is a new method that’s identical to the firstOrCreate() method but without waiting for the index to refresh.

$book = Book::firstOrCreateWithoutRefresh(
['title' => $title,'author' => $author], //$attributes
['description' => $description, 'stock' => 0] //values
);