Реалізація функції пошуку стала надзвичайно важливою для веб-додатків, які цінують зручність користувачів, адже це дозволяє шукати необхідну інформацію без нескінченного прокручування
У цьому посібнику ми створимо додаток для перегляду фільмів, використовуючи MongoDB Atlas Search та Laravel (популярний PHP-фреймворк), щоб побудувати зручну текстову функцію пошуку, що дозволить користувачам знаходити фільми, вводячи кілька символів
Гнучка схема MongoDB, можливості Atlas Search і потужні запитувачі в поєднанні з експресивним синтаксисом Laravel дозволяють нам швидко впроваджувати розширені функції пошуку
Джерело цього додатку можна знайти на GitHub
Щоб налаштувати наше середовище MongoDB, створіть кластер бази даних, налаштуйте доступ до бази та отримайте рядок підключення, дотримуючись інструкцій з офіційної документації MongoDB
Після налаштування кластера завантажте доказові дані, з якими ми будемо працювати, та отримайте наш рядок підключення
Ваш рядок підключення має виглядати так:
mongodb+srv://user:password@cluster0.xxxxx.mongodb.net
Після виконання вказаних вище кроків доказові дані повинні бути завантаженими у ваш кластер. Якщо ні, ознайомтеся з документацією про завантаження доказових даних
Після успішного завантаження даних у нас повинна бути база даних під назвою sample_mflix
у нашому кластері. Ми будемо працювати з колекцією movies у базі даних
Після налаштування бази даних створимо проект Laravel за допомогою Composer. Для цього вам потрібно переконатися, що PHP, Laravel, Node, npm, Composer і розширення PHP для MongoDB коректно налаштовані. Посилання нижче будуть корисними
Ознайомтеся з інструкціями з інтеграції MongoDB та Laravel. Вони пояснюють, як налаштувати середовище розробки Laravel-MongoDB. Далі ми розглянемо створення додатку Laravel і налаштування MongoDB
Коли наше середовище розробки готове, створимо проект Laravel за допомогою Composer. Виконайте наступну команду в терміналі у вибраному каталозі
composer create-project laravel/laravel movieapp
Ця команда створить новий проект Laravel у папці movieapp
. Після завершення встановлення ваша структура папок повинна виглядати так:
Запустіть сервер, виконуючи наступну команду в терміналі
cd movieapp
php artisan serve
Коли сервер запуститься, він буде доступний за адресою http://localhost:8000/
. Ви повинні побачити стартову сторінку Laravel, як показано нижче
Також у новому вікні терміналу запустіть команду для запуску фронтенд-сервера.
npm install
npm run dev
Тепер, коли наш сервер запущений, давайте підключимося до нашого кластера MongoDB
Щоб підключити сервер до раніше створеного кластера MongoDB, дотримуйтеся таких кроків:
composer require mongodb/laravel-mongodb
Це додасть пакет MongoDB до каталогу vendor
mongodb/builder
. Ми використовуватимемо його для побудови конвеєра агрегації. Виконайте наступну команду для додавання mongodb/builder
composer require mongodb/builder:^0.2
.env
. Оновіть значення DB_CONNECTION
та додайте DB_URI
так:DB_CONNECTION=mongodb
DB_URI=mongodb_connection_string_here
Замініть текст mongodb_connection_string_here
на ваш рядок підключення до бази даних
config/database.php
та оновіть масив connections
так:'connections' => [
'mongodb' => [
'driver' => 'mongodb',
'dsn' => env('DB_URI'),
'database' => 'sample_mflix',
],
config/database.php
оновіть рядок default
так:'default' => env('DB_CONNECTION'),
Це налаштує MongoDB як основне з'єднання для додатку
Тепер давайте створимо маршрут у /routes/web.php
:
<?php
use Illuminate\Support\Facades\Route;
// Імпортуємо клас Request
use Illuminate\Http\Request;
// Імпортуємо фасад DB
use Illuminate\Support\Facades\DB;
Route::get('/', function () {
return view('welcome');
});
// Додаємо маршрут перевірки з'єднання
Route::get('/connect', function (Request $request) {
$connection = DB::connection('mongodb');
$msg = 'MongoDB доступний!';
try {
$connection->getMongoClient()
->selectDatabase($connection->getDatabaseName())
->command(['ping' => 1]);
} catch (\Exception $e) {
$msg = 'MongoDB недоступний. Помилка: ' . $e->getMessage();
}
return response()->json(['msg' => $msg]);
});
У терміналі виконайте php artisan route
Ви повинні побачити маршрут у списку. У браузері перейдіть за адресою http://localhost:8000/connect/. Ви повинні побачити повідомлення про успіх {"msg":"MongoDB доступний!"}
Створимо Eloquent модель для нашої бази даних MongoDB під назвою "Movie", оскільки ми працюватимемо з колекцією movies
. За замовчуванням Eloquent вважатиме, що модель Movie
містить документи в колекції movies
. Виконайте команду в каталозі проекту, щоб створити модель Movie
php artisan make:model Movie
Після завершення команди буде створено файл /app/Models/Movie.php
. Відкрийте файл і оновіть його так:
<?php
namespace App\Models;
use MongoDB\Laravel\Eloquent\Model;
class Movie extends Model
{
protected $connection = 'mongodb';
}
Тепер давайте відобразимо кілька фільмів на нашій домашній сторінці
Для цього оновіть файл /routes/web.php
:
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Movie;
Route::get('/', function () {
$movies = Movie::limit(20)->get(); // Отримати тільки 20 фільмів
return view('welcome', [
'movies' => $movies
]);
});
Потім оновіть тег body
у файлі app/resources/views/welcome.blade.php
так:
<body class="font-sans antialiased dark:bg-black dark:text-white/50">
<div class="bg-gray-50 text-black/50 dark:bg-black dark:text-white/50">
<img id="background" class="absolute -left-20 top-0 max-w-[877px]"
src="https://laravel.com/assets/img/welcome/background.svg" alt="Laravel background" />
<div
class="relative min-h-screen flex flex-col items-center justify-center selection:bg-[#FF2D20] selection:text-white">
<div class="relative w-full max-w-2xl px-6 lg:max-w-7xl">
<div id="movie-list" class=' w-full flex gap-6 justify-around items-center flex-wrap'>
</div>
</div>
</div>
<script>
let movies = @json($movies);
displayMovies(movies)
function displayMovies(movies) {
const movieListDiv = document.getElementById('movie-list');
movieListDiv.innerHTML = movies.map(movie => `
<div class="movie-card max-w-sm bg-green-500 border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
<div class="h-[400px]">
<img class="rounded-t-lg object-cover w-full h-full" src="${movie.poster}" alt="${movie.title}" />
</div>
<div class="p-5">
<a href="#">
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white line-clamp-1">
${movie.title}
</h5>
</a>
<p class="mb-3 font-normal text-gray-700 dark:text-gray-400 line-clamp-2">${movie.plot}</p>
<a href="#"
class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Дивитися більше
</a>
</div>
</div>
`).join('');
}
</script>
</body>
Оновіть вашу програму за адресою http://localhost:8000. Ви повинні побачити список фільмів на екрані, як показано нижче
Якщо ви отримали помилку E11000 duplicate key error collection: sample_mflix.sessions index: user_id_1 dup key: { user_id: null }, перейдіть до колекції sessions у базі даних sample_mflix
, очистіть документ і спробуйте знову
Тепер, коли застосунок працює, давайте перейдемо до панелі керування MongoDB Atlas, щоб створити індекс для пошуку. Але спочатку…
Щоб реалізувати функцію пошуку фільмів за їх заголовками, створимо індекс пошуку на панелі керування MongoDB Atlas
У створеному раніше кластері перейдіть до вкладки Browse collections, далі до вкладки Atlas Search та натисніть Create index праворуч на сторінці пошуку. На цій сторінці виберіть JSON editor під Atlas Search, натисніть Next, введіть ім'я індексу (у нашому випадку movie_search
), виберіть колекцію films з бази даних sample_mflix
та оновіть JSON editor так, як показано нижче. Натисніть Next
{
"mappings": {
"dynamic": false,
"fields": {
"title": {
"type": "string"
}
}
}
}
Наступним кроком створимо ще один індекс, але цього разу тип буде автозаповнення. Ми будемо використовувати його, щоб реалізувати можливість підказки назв фільмів, коли користувач вводить текст
Створіть ще один індекс, дайте йому ім'я (у нашому випадку movie_title_autocomplete
), та оновіть JSON editor так:
{
"mappings": {
"dynamic": false,
"fields": {
"title": {
"type": "autocomplete"
}
}
}
}
Давайте створимо дві функції — searchByTitle
та autocompleteByTitle
в класі моделі Movie. Ці функції реалізують відповідно функції пошуку та автозаповнення
Оновимо файл app/Models/Movie.php
так:
<?php
namespace App\Models;
use Illuminate\Support\Collection;
use MongoDB\Laravel\Eloquent\Model;
class Movie extends Model
{
protected $connection = 'mongodb';
public static function searchByTitle(string $input): Collection
{
return self::aggregate()
->search([
'index' => 'movie_search',
'compound' => [
'must' => [
[
'text' => [
'query' => $input,
'path' => 'title',
'fuzzy' => ['maxEdits' => 2] // Додаємо нечітке співпадіння
]
]
]
]
])
->limit(20)
->project(title: 1, genres: 1, poster: 1, rated: 1, plot: 1)
->get();
}
public static function autocompleteByTitle(string $input): Collection
{
return self::aggregate()
->search([
'index' => 'movie_title_autocomplete',
'autocomplete' => [
'query' => $input,
'path' => 'title'
],
'highlight' => [
'path' => ['title']
]
])
->limit(5) // Обмежити результат до 5
->project(title: 1, highlights: ['$meta' => 'searchHighlights'])
->get();
}
}
Примітка: розміщення коду, що виконує запит на пошук, у класі моделі відокремлює рівень доступу до даних від HTTP контролерів. Це робить код більш тестованим
Давайте створимо контролер для реалізації API пошуку в проекті. Виконайте наступну команду для створення контролера
php artisan make:controller SearchController
Ця команда створить файл app/Http/Controllers/SearchController.php
. Оновіть файл так:
<?php
namespace App\Http\Controllers;
use App\Models\Movie;
use Illuminate\Http\JsonResponse;
class SearchController extends Controller
{
public function search($search): JsonResponse
{
// Визначаємо агрегацію на основі умов пошуку
if (!empty($search)) {
$items = Movie::searchByTitle($search);
return response()->json($items, 200);
}
return response()->json(['error' => 'умови не виконано'], 400);
}
}
Тепер давайте створимо API маршрут
Перейдіть до app/routes/web.php
:
// імпортуємо SearchController
use App\Http\Controllers\SearchController;
Route::get('/search/{search}', [SearchController::class, 'search']);
Тестуйте API, викликаючи його, наприклад:
http://localhost:8000/search/moving train
Перейдіть до файлу app/Http/Controllers/SearchController.php
та додайте нижче функцію після закінчення функції search
public function autocomplete($param): JsonResponse
{
try {
$results = Movie::autocompleteByTitle($param);
return response()->json($results, 200);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
Далі створіть API маршрут. Перейдіть до app/routes/web.php
Route::get('/autocomplete/{param}', [SearchController::class, 'autocomplete']);
Тестуйте API, викликавши його так:
http://localhost:8000/autocomplete/hello
Щоб побачити ці зміни в дії, оновіть тег body
у файлі app/resources/views/welcome.blade.php
так
Отримайте завершений фрагмент коду на GitHub
<body class="font-sans antialiased dark:bg-black dark:text-white/50">
<script>
let debounceTimer;
let movies = @json($movies);
displayMovies(movies)
function handleSearch(event) {
const query = event.target.value;
// Очищаємо попередній таймер
clearTimeout(debounceTimer);
// Встановлюємо новий таймер
debounceTimer = setTimeout(() => {
if (query.length > 2) { // Шукати тільки при введенні більше 2 символів
titleAutocomplete(query);
}
}, 300);
}
async function titleAutocomplete(query) {
try {
const response = await fetch(`/autocomplete/${encodeURIComponent(query)}`);
const movies = await response.json();
displayResults(movies);
} catch (error) {
console.error('Помилка при отриманні фільмів:', error);
}
}
async function fetchMovies(query) {
try {
const response = await fetch(`/search/${encodeURIComponent(query)}`);
const movies = await response.json();
displayMovies(movies);
displayResults([]);
} catch (error) {
console.error('Помилка при отриманні фільмів:', error);
}
}
function displayResults(movies) {
const resultsDiv = document.getElementById('search-results');
resultsDiv.innerHTML = movies.map(movie => `
<div onclick="fetchMovies('${movie.title}')" class='select-none text-gray-600 cursor-pointer flex items-center gap-[10px]'>
<div>
${movie.title}
</div>
</div>`).join('');
}
function displayMovies(movies) {
const movieListDiv = document.getElementById('movie-list');
movieListDiv.innerHTML = movies.map(movie => `
<div class="movie-card max-w-sm bg-green-500 border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
<div class="h-[400px]">
<img class="rounded-t-lg object-cover w-full h-full" src="${movie.poster}" alt="${movie.title}" />
</div>
<div class="p-5">
<a href="#">
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white line-clamp-1">
${movie.title}
</h5>
</a>
<p class="mb-3 font-normal text-gray-700 dark:text-gray-400 line-clamp-2">${movie.plot}</p>
<a href="#"
class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Дивитися більше
<svg class="rtl:rotate-180 w-3.5 h-3.5 ms-2" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9" />
</svg>
</a>
</div>
</div>
`).join('');
}
</script>
</body>
У зроблених змінах:
displayMovies
, яка приймає параметр movies. Вона відображає картки фільмів на екрані відповідно до наданого спискуhandleSearch
як обробник події oninput для поля пошукуhandleSearch
реалізовано функцію titleAutocomplete
, яка отримує та відображає дані з API для автозаповненняfetchMovies
, яка отримує дані з API для пошуку, за допомогою чого викликається функція displayMovies для відображення отриманих фільмівЗ усіма змінами перейдіть за адресою http://localhost:8000/ для тестування, як показано нижче
Важливо забезпечити простоту знаходження інформації вашими користувачами на веб-сайті для досягнення високої якості користувацького досвіду. У цьому посібнику я показав, як створити функцію текстового пошуку для додатку про фільми з використанням MongoDB Atlas Search, яка дозволяє користувачам шукати фільми за їхніми заголовками
Atlas Search є потужним механізмом повнотекстового пошуку, що надає розробникам можливість впроваджувати багатий функціонал пошуку в свої додатки. Це дозволяє швидко і ефективно шукати великі обсяги даних
Дізнайтеся більше про MongoDB Atlas Search та використання PHP з MongoDB
```