Работа с результатами поиска

Поисковые сервисы HERE Maps API позволяют получать географические объекты по текстовым запросам, координатам, категориям и различным фильтрам. После выполнения поискового запроса основной задачей становится корректная обработка полученных данных: извлечение нужной информации, отображение на карте, организация пользовательской навигации и выполнение последующих действий на основе найденных объектов.

Большинство поисковых операций выполняется через сервис Search API, который возвращает результаты в формате JSON. Каждый найденный объект содержит набор метаданных, необходимых для дальнейшей работы приложения.

Пример результата поиска:

{
  "items": [
    {
      "title": "Central Park",
      "id": "here:pds:place:12345",
      "resultType": "place",
      "address": {
        "label": "Central Park, New York, NY, USA"
      },
      "position": {
        "lat": 40.785091,
        "lng": -73.968285
      }
    }
  ]
}

Массив items содержит список найденных объектов.


Получение результатов через Discover API

Наиболее распространённым способом поиска является метод discover().

const service = platform.getSearchService();

service.discover(
{
    q: "coffee",
    at: "40.7128,-74.0060"
},
(result) => {
    console.log(result.items);
},
(error) => {
    console.error(error);
}
);

После успешного выполнения запроса массив найденных объектов становится доступен через свойство:

result.items

Каждый элемент массива представляет отдельный объект поиска.


Структура объекта результата

Типичный объект содержит следующие поля:

{
    title: "Starbucks",
    id: "here:af:streetsection:123456",
    resultType: "place",
    position: {
        lat: 40.7123,
        lng: -74.0045
    },
    address: {
        label: "New York, NY, USA"
    },
    categories: [...],
    contacts: [...],
    distance: 250
}

Основные свойства

Свойство Назначение
title Название объекта
id Уникальный идентификатор
resultType Тип результата
position Географические координаты
address Адрес объекта
distance Расстояние от точки поиска
categories Категории объекта
contacts Контактные данные

Перебор найденных объектов

Чаще всего результаты обрабатываются циклом.

Использование forEach

result.items.forEach((item) => {
    console.log(item.title);
});

Использование цикла for…of

for (const item of result.items) {
    console.log(item.title);
}

Создание массива названий

const names = result.items.map(item => item.title);

console.log(names);

Результат:

[
    "Starbucks",
    "Costa Coffee",
    "Coffee House"
]

Проверка наличия результатов

Поисковый запрос может не вернуть ни одного объекта.

if (result.items.length === 0) {
    console.log("Ничего не найдено");
}

Без подобной проверки возможно возникновение ошибок при попытке обращения к первому элементу массива.


Получение первого результата

Во многих сценариях требуется только наиболее релевантный объект.

const firstResult = result.items[0];

console.log(firstResult.title);

Перед обращением необходимо убедиться, что массив не пуст.

if (result.items.length > 0) {
    const firstResult = result.items[0];
}

Извлечение координат найденного объекта

Координаты используются для центрирования карты и построения маршрутов.

const item = result.items[0];

const lat = item.position.lat;
const lng = item.position.lng;

console.log(lat, lng);

Также возможно использовать деструктуризацию:

const { lat, lng } = item.position;

Центрирование карты по найденному объекту

После получения координат карта может автоматически переместиться к найденному месту.

map.setCenter(item.position);
map.setZoom(15);

Более компактный вариант:

map.getViewModel().setLookAtData({
    position: item.position,
    zoom: 15
});

Отображение результатов маркерами

Каждый найденный объект можно визуализировать на карте.

result.items.forEach((item) => {

    const marker = new H.map.Marker(item.position);

    map.addObject(marker);

});

В результате все найденные точки будут отображены на карте.


Добавление информационных окон

Для отображения дополнительной информации используются объекты UI.

const marker = new H.map.Marker(item.position);

marker.setData(item.title);

marker.addEventListener("tap", (event) => {

    const bubble = new H.ui.InfoBubble(
        event.target.getGeometry(),
        {
            content: event.target.getData()
        }
    );

    ui.addBubble(bubble);

});

map.addObject(marker);

При нажатии на маркер появляется информационное окно.


Отображение адреса найденного объекта

Полный адрес содержится в объекте address.

console.log(item.address.label);

Пример значения:

1600 Amphitheatre Parkway,
Mountain View, CA, USA

Работа с расстоянием до объекта

Если поиск выполняется относительно координат, HERE может вернуть расстояние до результата.

console.log(item.distance);

Пример:

250

Значение измеряется в метрах.

Для отображения в километрах:

const km = (item.distance / 1000).toFixed(1);

Фильтрация результатов

После получения данных можно оставить только нужные объекты.

Фильтрация по расстоянию

const nearby = result.items.filter(item => {
    return item.distance < 1000;
});

Останутся объекты в радиусе одного километра.

Фильтрация по названию

const cafes = result.items.filter(item => {
    return item.title.includes("Coffee");
});

Сортировка результатов

По расстоянию

const sorted = result.items.sort((a, b) => {
    return a.distance - b.distance;
});

По алфавиту

const sorted = result.items.sort((a, b) => {
    return a.title.localeCompare(b.title);
});

Ограничение количества результатов

Иногда необходимо отображать только часть найденных объектов.

const firstFive = result.items.slice(0, 5);

Либо:

const topThree = result.items.slice(0, 3);

Формирование пользовательского списка

Результаты поиска часто выводятся рядом с картой.

const list = document.getElementById("results");

result.items.forEach(item => {

    const li = document.createElement("li");

    li.textContent = item.title;

    list.appendChild(li);

});

Связывание списка с картой

При выборе элемента списка карта может автоматически переходить к соответствующему объекту.

li.addEventListener("click", () => {

    map.setCenter(item.position);

    map.setZoom(16);

});

Так создаётся синхронизация между интерфейсом и картой.


Использование уникального идентификатора

Каждый объект содержит поле id.

console.log(item.id);

Пример:

here:pds:place:123456789

Идентификатор может использоваться для:

  • сохранения избранных мест;
  • повторного запроса данных;
  • привязки объекта к базе данных приложения;
  • кэширования результатов.

Определение типа найденного объекта

Поле resultType показывает природу результата.

console.log(item.resultType);

Возможные значения:

place
street
locality
houseNumber
administrativeArea

Пример проверки:

if (item.resultType === "place") {
    console.log("Найдено место");
}

Работа с категориями

Многие объекты содержат информацию о категориях.

console.log(item.categories);

Пример структуры:

[
    {
        id: "100-1000",
        name: "Restaurant"
    }
]

Получение названий категорий:

const categoryNames = item.categories.map(
    category => category.name
);

console.log(categoryNames);

Получение контактной информации

Для коммерческих объектов доступны контакты.

console.log(item.contacts);

Возможные данные:

  • телефоны;
  • сайты;
  • электронная почта;
  • социальные сети.

Получение телефона:

const phone = item.contacts[0].phone[0].value;

Перед обращением необходимо проверять наличие данных.

if (
    item.contacts &&
    item.contacts.length > 0
) {
    console.log(item.contacts);
}

Асинхронная обработка результатов через Promise

Для удобства callback-механизм можно обернуть в Promise.

function search(query) {

    return new Promise((resolve, reject) => {

        service.discover(
        {
            q: query,
            at: "40.7128,-74.0060"
        },
        resolve,
        reject
        );

    });

}

Использование:

const result = await search("museum");

console.log(result.items);

Такой подход упрощает интеграцию поисковых запросов в современные приложения.


Группировка результатов по категориям

Иногда требуется разделить результаты на группы.

const grouped = {};

result.items.forEach(item => {

    const category =
        item.categories?.[0]?.name || "Other";

    if (!grouped[category]) {
        grouped[category] = [];
    }

    grouped[category].push(item);

});

Полученная структура:

{
    Restaurant: [...],
    Hotel: [...],
    Museum: [...]
}

Обработка ошибок поиска

Любой поисковый запрос должен содержать обработчик ошибок.

service.discover(
{
    q: "hotel",
    at: "40.7128,-74.0060"
},
(result) => {
    console.log(result);
},
(error) => {
    console.error("Ошибка поиска:", error);
}
);

Распространённые причины ошибок:

  • некорректный API Key;
  • превышение лимитов;
  • отсутствие сетевого соединения;
  • неверный формат параметров;
  • ошибки авторизации.

Очистка предыдущих результатов

Перед новым поиском часто требуется удалить старые маркеры.

map.removeObjects(map.getObjects());

После очистки можно отображать новые результаты.

result.items.forEach(item => {

    map.addObject(
        new H.map.Marker(item.position)
    );

});

Автоматическое масштабирование под все результаты

Если найдено несколько объектов, удобно показать их одновременно.

const group = new H.map.Group();

result.items.forEach(item => {

    group.addObject(
        new H.map.Marker(item.position)
    );

});

map.addObject(group);

map.getViewModel().setLookAtData({
    bounds: group.getBoundingBox()
});

Карта автоматически подберёт масштаб таким образом, чтобы все маркеры оказались в зоне видимости.


Построение маршрута к найденному объекту

Результаты поиска часто используются как конечная точка маршрута.

const destination = item.position;

Далее координаты передаются в Routing API:

routingService.calculateRoute({
    origin: "40.7128,-74.0060",
    destination:
        `${destination.lat},${destination.lng}`,
    transportMode: "car"
},
onSuccess,
onError
);

Так объединяются поисковые и навигационные возможности платформы HERE.


Практический сценарий обработки поиска

Полный цикл работы обычно выглядит следующим образом:

  1. Выполнение поискового запроса.
  2. Получение массива items.
  3. Проверка наличия результатов.
  4. Очистка предыдущих объектов карты.
  5. Создание маркеров.
  6. Формирование списка найденных мест.
  7. Добавление информационных окон.
  8. Автоматическое масштабирование карты.
  9. Сохранение идентификаторов найденных объектов.
  10. Передача выбранного результата в другие сервисы платформы.

Подобная схема лежит в основе большинства картографических приложений: сервисов доставки, навигаторов, туристических каталогов, систем мониторинга транспорта и корпоративных геоинформационных решений.