Panduan lengkap untuk pencarian real-time di Laravel

Pembaharuan Terakhir: Desember 5 2025
  • Laravel memungkinkan Anda mengimplementasikan semuanya mulai dari mesin pencari sederhana dengan AJAX hingga pencarian teks lengkap tingkat lanjut menggunakan Laravel Scout dan mesin pencari eksternal seperti Algolia, Meilisearch, atau Elasticsearch.
  • Untuk pencarian ringan, pemfilteran pada frontend dengan Alpine.js atau dengan permintaan pengambilan asli menghindari kelebihan beban pada server dan meningkatkan pengalaman pengguna dalam daftar kecil.
  • Laravel Scout memusatkan integrasi dengan berbagai mesin pencari dan memudahkan untuk menandai model sebagai dapat dicari, mengelola indeks, dan meluncurkan kueri secara seragam.
  • Pilihan mesin (SaaS, sumber terbuka atau basis data) harus didasarkan pada volume data, kompleksitas pencarian, dan persyaratan kinerja serta pemeliharaan proyek.

pencarian waktu nyata di Laravel

Saat Anda mulai bekerja dengan Laravel dan membutuhkan mesin pencari real-time yang merespons secara instan , mudah untuk tersesat di antara ribuan pendekatan yang mungkin: AJAX dengan fetch, jQuery, Alpine.js, Scout dengan Algolia atau Meilisearch, penyaringan frontend, dll. Kabar baiknya adalah ekosistem Laravel sudah menyediakan hampir semua yang Anda butuhkan untuk membangun mesin pencari yang lancar dan cepat tanpa merasa kewalahan.

Dalam artikel ini, Anda akan mempelajari cara mengimplementasikan berbagai jenis pencarian waktu nyata di Laravel , mulai dari autocomplete AJAX klasik hingga pencarian teks lengkap menggunakan Laravel Scout dan mesin pencari seperti Algolia, Meilisearch, basis data itu sendiri, atau bahkan Elasticsearch. Anda juga akan menjelajahi alternatif ringan dengan Alpine.js untuk memfilter data langsung di browser saat berurusan dengan kumpulan data kecil.

Apa itu pencarian real-time di Laravel dan bagaimana cara kerja dasarnya?

Ide di balik pencarian waktu nyata adalah bahwa, saat pengguna mengetik di kolom teks , sebuah kueri dipicu dan hasilnya diperbarui tanpa memuat ulang halaman. Secara teknis, ini melibatkan tiga komponen utama: backend Laravel, JavaScript browser, dan pertukaran data dalam format JSON.

Di satu sisi, Laravel bertindak sebagai lapisan server yang bertanggung jawab untuk menerima permintaan, menginterpretasikan parameter pencarian (teks yang dimasukkan), melakukan query ke database, dan mengembalikan respons terstruktur, biasanya dalam format JSON. Respons ini dapat menunjukkan keberhasilan, kesalahan, atau bahwa tidak ada hasil yang ditemukan.

Di sisi lain, JavaScript menangani pendengaran peristiwa pengguna pada input pencarian, mengirim permintaan asinkron (AJAX) ke backend, dan menampilkan data yang dikembalikan di halaman tanpa memerlukan penyegaran browser penuh. Hal ini dapat dilakukan dengan fetch bawaan, jQuery AJAX, atau pustaka reaktif kecil seperti Alpine.js.

Dengan mekanisme dasar ini, Anda dapat membangun apa saja, mulai dari fitur pelengkapan otomatis sederhana dengan beberapa data , hingga mesin pencari teks lengkap tingkat lanjut dengan relevansi, penomoran halaman, dan filter, dengan mengandalkan pustaka seperti Laravel Scout dan mesin pencari eksternal yang dioptimalkan untuk pencarian.

Model, rute, dan pengontrol untuk mesin pencari waktu nyata dasar

Sebelum Anda mempelajari JavaScript lebih dalam, Anda perlu menyiapkan sisi Laravel dengan baik: model Eloquent untuk pencarian, rute yang jelas, dan controller yang khusus menangani logika pencarian secara real-time.

Langkah pertama adalah memiliki model Eloquent yang mewakili tabel tempat Anda akan melakukan pencarian. Bayangkan sebuah tabel negara dan model yang sangat sederhana bernama Country , tanpa stempel waktu dan dengan penugasan massal yang diizinkan:

Contoh model Eloquent minimal untuk pencarian :

namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Pais extends Model
{
use HasFactory;
protected $guarded = [];
public $timestamps = false;
}

Ini menunjukkan bahwa model Pais terletak di namespace Laravel standar , mewarisi dari Model, dan memungkinkan penugasan bidang apa pun dengan create() dengan membiarkan array yang dijaga kosong. Dengan menonaktifkan stempel waktu dengan public $timestamps = false, Anda menghindari masalah jika tabel tidak memiliki kolom created_at dan updated_at.

Langkah selanjutnya adalah menentukan rute yang akan menangani tampilan mesin pencari dan permintaan AJAX . Skema yang sangat umum menggabungkan rute GET untuk menampilkan tampilan dan rute POST yang dirancang untuk menerima kueri secara real-time:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BuscadorController;

Route::get('/', function () {
return view('welcome');
});

Route::get('buscador', [BuscadorController::class, 'index']);
Route::post('buscador', [BuscadorController::class, 'buscar']);

Rute utama mengembalikan tampilan selamat datang, sedangkan URL /search dikhususkan untuk fungsi pencarian . Metode index() pada controller menampilkan formulir dan input pencarian, sementara metode search() memproses permintaan asinkron yang dikirim dari browser.

Di dalam controller, Anda dapat menerapkan pola yang sangat praktis: siapkan array respons default jika terjadi kesalahan dan hanya timpa array tersebut ketika permintaan AJAX benar-benar valid dan kueri berjalan tanpa masalah.

Pengontrol tersebut dapat memiliki struktur yang mirip dengan ini:

namespace App\Http\Controllers;

use App\Models\Pais;
use Illuminate\Http\Request;

class BuscadorController extends Controller
{
public function index()
{
return view('welcome');
}

public function buscar(Request $request)
{
$response = [
'success' => false,
'message' => 'Hubo un error',
];

if ($request->ajax()) {
$data = Pais::where('nombre', 'like', $request->texto.'%')
->take(10)
->get();

$response = [
'success' => true,
'message' => 'Consulta correcta',
'data' => $data,
];
}

return response()->json($response);
}
}

Pada titik ini, Anda memiliki siklus backend yang lengkap: permintaan AJAX masuk, verifikasi bahwa itu memang AJAX, kueri menggunakan `where like`, dan membatasi jumlah hasil hingga jumlah yang wajar dengan `take(10)` untuk menghindari kelebihan beban pada basis data. Respons selalu dikirim dalam format JSON, yang sangat menyederhanakan pekerjaan frontend.

Tampilan blade dan pengambilan JavaScript untuk pencarian reaktif

Setelah model, rute, dan controller siap, saatnya membangun bagian yang terlihat: sebuah formulir dengan kolom pencarian dan blok untuk menampilkan hasilnya , ditambah JavaScript yang bertanggung jawab untuk melakukan permintaan di latar belakang.

Tampilan Blade bisa sangat sederhana, mengandalkan token CSRF yang disuntikkan Laravel untuk memvalidasi permintaan POST dan pada input pencarian yang mudah digunakan:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<strong><meta name="csrf-token" content="{{ csrf_token() }}"></strong>
<title>Laravel</title>
</head>
<body>

<form action="" method="post">
<input type="search" name="texto" id="buscar">
</form>

<div id="resultado"></div>

<script>
window.addEventListener('load', function () {
const buscar = document.getElementById('buscar');
const resultado = document.getElementById('resultado');

buscar.addEventListener('keyup', function () {
fetch('/buscador', {
method: 'post',
body: JSON.stringify({ texto: buscar.value }),
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': document.head.querySelector('[name~="csrf-token"][content]').content,
},
})
.then(response => response.json())
.then(data => {
let html = '';
if (data.success) {
html += '<ul>';
for (let i in data.data) {
html += '<li>' + data.data[i].nombre + '</li>';
}
html += '<ul>';
} else {
html += 'No existen resultados';
}
resultado.innerHTML = html;
});
});
});
</script>

</body>
</html>

Dalam contoh ini, skrip mendengarkan peristiwa keyup pada input pencarian , sehingga setiap penekanan tombol memicu permintaan pengambilan data ke jalur /search. Teks saat ini dari kolom dikirim dalam format JSON, dan header penting seperti X-Requested-With disertakan untuk menunjukkan bahwa itu adalah AJAX, bersama dengan token CSRF untuk melewati perlindungan bawaan Laravel.

Saat respons tiba, respons tersebut diubah menjadi JSON dan daftar HTML kecil berisi hasilnya dibuat secara dinamis , atau pesan seperti "Tidak ada hasil ditemukan" ditampilkan jika kueri tidak mengembalikan data. Semua ini terjadi tanpa memuat ulang halaman, dengan cara yang alami bagi pengguna.

Pola ini dapat disempurnakan lebih lanjut dengan detail UX kecil, seperti menambahkan penundaan (debounce) antar penekanan tombol, menampilkan indikator pemuatan, atau menangani kesalahan jaringan untuk mencegah antarmuka tampak membeku ketika terjadi kegagalan.

Pencarian langsung dengan Laravel dan AJAX menggunakan jQuery

Meskipun fetch telah mendapatkan daya tarik yang signifikan, jQuery AJAX tetap sangat populer di proyek-proyek lama atau tim yang sudah mengintegrasikannya. Idenya persis sama: tangkap apa yang diketik pengguna, lakukan permintaan asinkron, dan perbarui DOM.

Alur kerja tipikal dengan jQuery di Laravel untuk pencarian langsung biasanya mencakup langkah-langkah dasar berikut: mendefinisikan rute tertentu, membuat controller khusus, membangun tampilan Blade dengan input pencarian , dan akhirnya menambahkan kode jQuery yang memicu AJAX saat diketik.

Prosesnya bekerja seperti ini: ketika pengguna mulai mengetik, jQuery mengirimkan kueri ke server dengan string pencarian. Laravel memfilter informasi dalam basis data, mengembalikan objek JSON dengan hasil yang cocok, dan jQuery memperbarui kontainer HTML di halaman untuk mencerminkan hasil yang cocok, semuanya dalam hitungan milidetik.

Keuntungan menggunakan jQuery adalah sangat menyederhanakan sintaks AJAX dan sangat mudah dibaca jika Anda sudah memiliki pustaka tersebut dalam proyek Anda. Namun, hal ini memperkenalkan ketergantungan tambahan yang mungkin tidak diperlukan jika Anda dapat bekerja dengan JavaScript modern dan fungsi fetch bawaan.

Pemfilteran dan pencarian waktu nyata di frontend dengan Alpine.js

Ketika data yang akan ditampilkan relatif kecil (misalnya, kurang dari 50 item ), tidak selalu bermanfaat untuk menyiapkan backend dengan pencarian yang kompleks. Dalam kasus ini, pilihan yang sangat nyaman adalah memfilter langsung di browser menggunakan Alpine.js , tanpa melakukan permintaan ke server saat pengguna mengetik.

Idenya adalah untuk menghitung terlebih dahulu string pencarian untuk setiap item (misalnya, nama, deskripsi, dan kategori dalam huruf kecil), menyimpannya dalam atribut data-search-text, dan membiarkan Alpine.js menangani menampilkan atau menyembunyikan item berdasarkan teks yang dimasukkan di kolom pencarian.

Komponen Alpine.js dapat memiliki struktur yang mirip dengan ini: filterItems

{
search: '',
hasResults: true,
selectedValue: '',
init() {
this.$watch('search', () => this.filterItems());
this.$nextTick(() => this.$refs.searchInput?.focus());
},
filterItems() {
const searchLower = this.search.toLowerCase().trim();
const cards = this.$el.querySelectorAll('.item-card');
let visibleCount = 0;

cards.forEach(card => {
const text = card.dataset.searchText || '';
const isVisible = searchLower === '' || text.includes(searchLower);
card.style.display = isVisible ? '' : 'none';
if (isVisible) visibleCount++;
});

this.hasResults = visibleCount > 0;
},
}

Dalam tampilan tersebut, setiap kartu atau baris data akan memiliki atribut data-search-text dengan teks yang sudah disiapkan dalam huruf kecil , sehingga filternya disederhanakan menjadi fungsi includes() di JavaScript, yang sangat cepat untuk daftar pendek:

<input type="search" x-model="search" x-ref="searchInput" placeholder="Buscar..." />
<div>
<div class="item-card" data-search-text="formulario contacto simple">
<h3>Formulario de contacto</h3>
<p>Formulario de contacto simple</p>
</div>
</div>

Selain itu, Anda dapat menampilkan blok status kosong hanya ketika tidak ada hasil untuk istilah pencarian saat ini , mengundang pengguna untuk mengubah teks atau menghapus kolom dengan tombol yang hanya mengatur ulang pencarian menjadi string kosong.

Pendekatan ini memiliki keunggulan yang jelas: tidak ada panggilan server selama pencarian , interaksi hampir instan, dan logika tetap sangat lokal dan mudah di-debug. Ini sempurna untuk pemilih cepat, modal pemilihan item, atau katalog kecil yang disematkan di halaman Laravel.

Laravel Scout: Pencarian teks lengkap dengan mesin khusus

Ketika situasinya menjadi serius dan Anda membutuhkan pencarian teks lengkap yang cepat, relevan, dan terukur , jalur alami di Laravel adalah Laravel Scout. Scout adalah lapisan integrasi yang memungkinkan Anda untuk dengan mudah menghubungkan model Eloquent Anda dengan mesin pencari seperti Algolia, Meilisearch, basis data Anda, koleksi dalam memori, atau bahkan Elasticsearch melalui pengontrol eksternal.

Untuk memulai menggunakan Scout, pendekatan yang umum adalah membuat proyek Laravel baru atau menggunakan kembali proyek yang sudah ada , menjalankannya dengan Docker (misalnya, menggunakan Laravel Sail), dan kemudian menginstal pustaka dengan Composer. Setelah itu, Anda mempublikasikan file konfigurasi scout.php dan menyesuaikan variabel lingkungan sesuai dengan driver yang ingin Anda gunakan.

Alur kerja tipikalnya adalah menginstal Scout dengan Composer, mempublikasikan konfigurasinya, dan mengaktifkan antrian pengindeksan dengan `SCOUT_QUEUE=true` di file `.env` sehingga operasi yang membutuhkan banyak sumber daya diproses di latar belakang, meningkatkan waktu respons aplikasi. Selain itu, Anda harus memastikan bahwa `DB_HOST` mengarah ke basis data yang Anda gunakan, yang sangat penting jika Anda menggunakan kontainer Docker.

Agar sebuah model dapat berpartisipasi dalam pencarian Scout, model tersebut harus secara eksplisit ditandai sebagai dapat dicari dengan menambahkan trait `Searchable` . Misalnya, jika Anda memiliki model `Train` yang merepresentasikan tabel kereta api dengan field `title`, Anda dapat mendefinisikannya seperti ini:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Train extends Model
{
use Searchable;

protected $fillable = ['title'];

public function searchableAs()
{
return 'trains_index';
}
}

Metode `searchableAs` memungkinkan Anda untuk menyesuaikan nama indeks di mesin pencari , alih-alih menggunakan nama default yang berasal dari model. Dari situ, Scout menangani sinkronisasi operasi pembuatan, pembaruan, dan penghapusan dengan indeks jarak jauh atau lokal, tergantung pada driver yang dipilih.

Laravel Scout dengan Algolia: Pencarian SaaS Secepat Kilat

Algolia adalah layanan SaaS yang berfokus pada penyediaan pencarian yang sangat cepat dan relevan di seluruh volume data yang besar . Layanan ini memiliki panel web untuk mengelola indeks, aturan relevansi, sinonim, dan banyak lagi, serta terintegrasi dengan mulus dengan Laravel melalui Scout dan klien PHP resmi.

Untuk menggunakan Algolia dengan Scout, Anda perlu menginstal klien PHP-nya menggunakan Composer, mendaftarkan kredensial Anda di file .env (ID Aplikasi dan Kunci API Admin), dan mengkonfigurasi SCOUT_DRIVER=algolia untuk memberi tahu Scout agar menggunakan mesin ini. Anda dapat memperoleh ID aplikasi dan kunci admin dari dasbor Algolia.

Setelah lingkungan disiapkan, Anda dapat menggunakan metode seperti Train::search('text')->paginate(6) langsung di controller Anda untuk melakukan pencarian pada field yang diindeks, menerima hasil dalam format Eloquent yang dipaginasi dan siap untuk diteruskan ke view Blade.

Sebagai contoh , Anda dapat memiliki controller indeks yang mencantumkan semua kereta atau melakukan pencarian jika parameter titlesearch dilewatkan, dan metode create untuk memasukkan kereta baru ke dalam indeks:

public function index(Request $request)
{
if ($request->has('titlesearch')) {
$trains = Train::search($request->titlesearch)->paginate(6);
} else {
$trains = Train::paginate(6);
}

return view('Train-search', compact('trains'));
}

public function create(Request $request)
{
$this->validate($request, ['title' => 'required']);
Train::create($request->all());
return back();
}

Pada tampilan yang sesuai, Anda dapat menggabungkan formulir untuk menambahkan kereta baru dan formulir GET lainnya dengan kolom pencarian judul yang memicu pencarian saat pengiriman. Kemudian Anda cukup mengulangi koleksi kereta dan menampilkan kolom-kolomnya dalam tabel, memanfaatkan tautan paginasi yang dihasilkan oleh Laravel.

Scout dengan Meilisearch, database dan koleksi

Jika Anda lebih suka menghindari layanan eksternal, Meilisearch adalah mesin pencari sumber terbuka yang dapat Anda terapkan secara lokal atau pada infrastruktur Anda. Scout terintegrasi dengan Meilisearch dengan cara yang sangat mirip dengan Algolia, hanya dengan mengubah driver dan menambahkan variabel MEILISEARCH_HOST dan MEILISEARCH_KEY ke file .env.

Untuk menggunakannya, instal klien PHP Meilisearch, atur SCOUT_DRIVER=meilisearch , dan arahkan MEILISEARCH_HOST ke URL instance (misalnya, http://127.0.0.1:7700). Jika Anda sudah memiliki data, Anda dapat mengindeksnya dengan perintah php artisan scout:import "App\Models\Train" agar mesin dapat mengaksesnya.

Untuk aplikasi berukuran kecil atau sedang, Anda juga dapat memilih driver basis data Scout , yang memanfaatkan indeks teks lengkap dan pernyataan LIKE pada basis data MySQL atau PostgreSQL Anda. Dalam hal ini, Anda tidak memerlukan layanan eksternal; cukup atur SCOUT_DRIVER=database agar Scout menggunakan basis data itu sendiri sebagai mesin pencarinya.

Opsi menarik lainnya adalah collection driver, yang bekerja dengan koleksi Eloquent dalam memori . Mesin ini menyaring hasil menggunakan `where` dan metode penyaringan koleksi, dan kompatibel dengan database apa pun yang didukung oleh Laravel. Anda dapat mengaktifkannya dengan `SCOUT_DRIVER=collection` atau dengan menyesuaikan file konfigurasi Scout jika Anda menginginkan sesuatu yang lebih spesifik.

Integrasi dengan Elasticsearch menggunakan Explorer

Jika kebutuhan pencarian Anda melibatkan pengolahan data dalam jumlah besar dan analitik waktu nyata , Elasticsearch adalah pilihan klasik. Dalam ekosistem Laravel, cara modern untuk mengintegrasikannya dengan Scout adalah dengan menggunakan controller Explorer, yang bertindak sebagai jembatan antara model Anda dan klaster Elasticsearch.

Biasanya, proses ini melibatkan penggunaan Docker dan file docker-compose yang lengkap yang meluncurkan, selain layanan standar (Laravel, MySQL, Redis, Meilisearch, dll.), kontainer Elasticsearch dan Kibana . Kemudian, Anda menginstal paket jeroen-g/explorer melalui Composer dan mempublikasikan file konfigurasinya untuk menentukan model mana yang harus diindeks.

Di dalam file config/explorer.php, Anda dapat mendaftarkan model Anda di bawah kunci indexes, misalnya dengan menambahkan App\Models\Train::class . Selain itu, Anda mengubah driver dari Scout menjadi Elasticsearch di file .env dengan SCOUT_DRIVER=elastic sehingga semuanya mengarah ke Elasticsearch.

Di dalam model Train, Anda perlu mengimplementasikan antarmuka Explored dan menimpa metode mappableAs , yang mendefinisikan peta bidang yang akan dikirim ke indeks. Contoh minimalnya adalah:

use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;

class Train extends Model implements Explored
{
use Searchable;

protected $fillable = ['title'];

public function mappableAs(): array
{
return [
'id' => $this->id,
'title' => $this->title,
];
}
}

Dari sini, Anda dapat meluncurkan pencarian di Elasticsearch menggunakan antarmuka Scout yang sama , memanfaatkan waktu respons yang sangat rendah dan kekuatan kueri penuh dari mesin ini, tetapi tanpa meninggalkan ekosistem Laravel.

Dengan semua pendekatan ini—mulai dari pelengkapan otomatis dasar dengan fetch atau jQuery, hingga pemfilteran frontend dengan Alpine.js, hingga pencarian teks lengkap dengan Laravel Scout dan berbagai driver— Laravel memberi Anda berbagai pilihan untuk mengimplementasikan pencarian waktu nyata yang disesuaikan dengan ukuran proyek Anda, kinerja yang Anda butuhkan, dan infrastruktur yang ingin Anda kelola.

  Cara Menggunakan Switch di Python: Panduan Lengkap dengan Contoh dan Alternatif