Работа с отзывами

Отзывы в экосистеме Google Maps Platform предоставляются через сервис Places и являются частью объекта места (Place). В JavaScript API они доступны либо через PlacesService (классический подход), либо через современный Place в новой версии Places API, интегрированной в Google Maps JavaScript API.

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

Каждый объект отзыва содержит следующие ключевые поля:

  • author_name — имя автора
  • rating — оценка от 1 до 5
  • text — текст отзыва
  • time — UNIX timestamp
  • relative_time_description — относительное время (например, “2 months ago”)
  • profile_photo_url — фото профиля (в зависимости от API)
  • language — язык отзыва (не всегда гарантирован)

Получение отзывов через PlacesService

Классический способ работы основан на google.maps.places.PlacesService. Отзывы возвращаются через метод getDetails.

Обязательное условие — указание поля reviews в параметре fields.

const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 48.0, lng: 66.9 },
  zoom: 12,
});

const service = new google.maps.places.PlacesService(map);

const request = {
  placeId: "ChIJN1t_tDeuEmsRUsoyG83frY4",
  fields: ["name", "rating", "reviews", "formatted_address"]
};

service.getDetails(request, (place, status) => {
  if (status === google.maps.places.PlacesServiceStatus.OK) {
    console.log(place.reviews);
  }
});

Поле reviews будет отсутствовать, если:

  • у места нет отзывов
  • API не получил доступ к данным
  • не указано поле reviews в запросе

Получение отзывов через Place (новый API)

В обновлённой версии Places API используется объект Place, который обеспечивает более структурированный доступ к данным.

const place = new google.maps.places.Place({
  id: "ChIJN1t_tDeuEmsRUsoyG83frY4"
});

await place.fetchFields({
  fields: ["displayName", "rating", "reviews"]
});

console.log(place.reviews);

В этой модели данные возвращаются более консистентно, а структура отзывов ближе к объектной модели SDK.


Структура объекта Review

Каждый отзыв представляет собой объект следующего вида:

{
  author_name: "John Doe",
  rating: 5,
  text: "Excellent service and great atmosphere.",
  time: 1700000000,
  relative_time_description: "2 months ago",
  profile_photo_url: "https://..."
}

В некоторых случаях поле text может быть пустым, если пользователь оставил только оценку без комментария.


Ограничения и особенности

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

Возвращается не более 5 отзывов. Это фиксированное ограничение API, изменить его невозможно.

Отсутствие сортировки

API не предоставляет параметров сортировки отзывов. Все операции сортировки выполняются на стороне клиента:

const sorted = place.reviews.sort((a, b) => b.rating - a.rating);

Или по времени:

const sortedByTime = place.reviews.sort((a, b) => b.time - a.time);

Атрибуция

Отзывы являются пользовательским контентом, и при их отображении требуется сохранять атрибуцию Google Maps. Обычно это реализуется через отображение логотипа или текстового упоминания источника.


Отображение отзывов в интерфейсе

Типичная схема рендеринга включает список карточек.

function renderReviews(reviews) {
  const container = document.getElementById("reviews");

  container.innerHTML = "";

  reviews.forEach(review => {
    const el = document.createElement("div");
    el.className = "review";

    el.innerHTML = `
      <div class="author">${review.author_name}</div>
      <div class="rating">Rating: ${review.rating}</div>
      <div class="text">${review.text || ""}</div>
      <div class="time">${review.relative_time_description}</div>
    `;

    container.appendChild(el);
  });
}

Работа с отсутствующими данными

Отзывы могут быть частично заполнены. Корректная обработка включает проверки:

  • отсутствие reviews
  • пустой массив
  • отсутствующий текст
  • некорректный рейтинг
if (!place.reviews || place.reviews.length === 0) {
  console.log("Отзывы отсутствуют");
}

Использование отзывов вместе с маркерами

Частый сценарий — загрузка отзывов по клику на маркер.

marker.addListener("click", () => {
  service.getDetails({
    placeId: marker.placeId,
    fields: ["name", "reviews"]
  }, (place, status) => {
    if (status === google.maps.places.PlacesServiceStatus.OK) {
      renderReviews(place.reviews);
    }
  });
});

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


Производительность и кэширование

Запросы getDetails относятся к более дорогим операциям API. При частом обращении к одним и тем же placeId применяется локальное кэширование:

const cache = new Map();

function getPlaceDetails(placeId, callback) {
  if (cache.has(placeId)) {
    callback(cache.get(placeId));
    return;
  }

  service.getDetails({
    placeId,
    fields: ["reviews", "rating"]
  }, (place, status) => {
    if (status === google.maps.places.PlacesServiceStatus.OK) {
      cache.set(placeId, place);
      callback(place);
    }
  });
}

Языковая локализация отзывов

Отзывы возвращаются в языке, привязанном к пользователю или месту. Повлиять на язык можно через параметр language в загрузке Maps API.

const service = new google.maps.places.PlacesService(map, {
  language: "ru"
});

Это не гарантирует перевод всех отзывов, но влияет на локализацию интерфейсных элементов и части данных.


Обработка изображений авторов

Поле profile_photo_url требует осторожной работы: изображение может отсутствовать или требовать дополнительной загрузки через прокси или с ограничениями CORS.

const img = document.createElement("img");
img.src = review.profile_photo_url || "/default-avatar.png";

Объединение рейтинга и отзывов

Отзывы часто используются совместно с агрегированным рейтингом:

console.log(place.rating);
console.log(place.user_ratings_total);

Эти поля позволяют строить интерфейсы, где краткая оценка дополняется детальными комментариями пользователей.


Фильтрация на клиенте

Поскольку API не предоставляет фильтров, их реализуют вручную:

const positiveReviews = place.reviews.filter(r => r.rating >= 4);
const negativeReviews = place.reviews.filter(r => r.rating <= 2);

Это особенно полезно при создании аналитических интерфейсов или карточек с быстрым обзором качества места.


Типичные ошибки при работе с отзывами

  • отсутствие fields: ["reviews"] в запросе
  • попытка получить больше 5 отзывов
  • ожидание серверной сортировки
  • игнорирование возможного undefined у текста
  • неправильная обработка async-ответов getDetails

Интеграция с пользовательским UI

Отзывы часто встраиваются в информационные окна InfoWindow:

const infoWindow = new google.maps.InfoWindow();

infoWindow.setContent(`
  <h3>${place.name}</h3>
  <div>Rating: ${place.rating}</div>
  <div>${place.reviews?.[0]?.text || ""}</div>
`);

Такой подход используется для быстрого отображения одного-двух ключевых отзывов без перегрузки интерфейса.