---
metadata:
  - name: generator
    content: Diplodoc Platform v5.39.1
alternate:
  - https://yandex.com/dev/jsapi-v2-1/doc/en/v2-1/dg/concepts/loading-object-manager/backend.md
  - https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/loading-object-manager/backend.md
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.com/dev/jsapi-v2-1/doc/ru/llms.txt

# Разработка серверной части

[LoadingObjectManager](https://tech.yandex.ru/maps/d../../jsapi/doc/2.1/ref/reference/LoadingObjectManager-docpage/) производит все операции с объектами на стороне клиента. К таким операциям относятся: создание оверлеев, их отрисовка, кластеризация объектов и т. д. Однако информация об объектах хранится на сервере, и менеджер будет обращаться к нему для получения нужных данных.

Для работы с `LoadingObjectManager` разработчику необходимо самостоятельно спроектировать архитектуру серверной части:

1. [Организовать хранение данных на сервере](#data-structure).

1. [Настроить обработку запросов, поступающих от клиентской части](#requests-format).

1. [Настроить ответ сервера в нужном формате](#response-format).


## Размещение данных на сервере {#data-structure}

Для хранения информации о географических объектах целесообразно использовать [пространственные базы данных](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B1%D0%B0%D0%B7%D0%B0_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85). Для многих СУБД существуют расширения, позволяющие организовывать доступ к пространственным объектам. Например, для [MySQL](http://dev.mysql.com/doc/) — это [SPATIAL](http://dev.mysql.com/doc/refman/5.7/en/spatial-extensions.html), для [PostgreSQL](http://www.postgresql.org/) — [PostGIS](http://www.postgis.org/). Также пространственные индексы поддерживают и другие стандартные базы данных, например, [Oracle](http://www.oracle.com/technetwork/database/enterprise-edition/documentation/index.html), [MongoDB](http://docs.mongodb.org/manual/).

Структура размещения данных зависит от выбранного [режима загрузки данных](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/loading-object-manager/loading-mode.md). Ниже рассмотрены запросы, которые менеджер будет отправлять на сервер при разных режимах, а также приведены рекомендации по организации структуры хранения данных.


## Обработка запросов менеджера  {#requests-format}

В зависимости от того, каким способом менеджер будет запрашивать данные (для всей видимой области сразу или по тайлам, по географическим координатам или по номерам тайлов), на сервер будут отправляться GET-запросы с разными параметрами. Ниже рассмотрены форматы запросов, которые менеджер будет отправлять на сервер при разных способах загрузки данных:

{% cut "1. Данные запрашиваются сразу для всей видимой области по ее географическим координатам" %}

![](../../_images/bbox_splitRequests_false.png)

Пример запроса, который отправит менеджер:

```
GET https://my-server.ru/?bbox=55.3589,36.2109,56.1519,39.0234&callback=myCallback_55_3589_36_2109_56_1519_39_0234
```

где:

- `bbox` – координаты левого нижнего и правого верхнего углов области;
- `callback` – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе [Формат ответа сервера](#response).

Чтобы менеджер запрашивал данные таким способом, необходимо при создании менеджера:
 
- в параметре [urlTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md) использовать подстановку `%b`.

Например:

```javascript
// Создадим менеджер и передадим ему шаблон URL данных.
// В шаблоне будем использовать подстановку %b, которая
// заменяется на массив географических координат области (подробнее о подстановках).
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?bbox=%b', {
        // Шаблон названия callback-функции, в которую сервер должен обернуть ответ.
        paddingTepmlate: "myCallback_%b"
    });
```

**Рекомендации по размещению данных на сервере**

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


{% endcut %}

{% cut "2. Данные запрашиваются сразу для всей видимой области по номерам угловых тайлов" %}

![](../../_images/tileBounds_splitRequests_false.png)

Пример запроса, который отправит менеджер за данными:

```
GET https://server.ru/?tileBounds=615,319,622,322&z=10&callback=myCallback_615_319_622_322_10 
```

где:
- `tileBounds` – номера левого верхнего и правого нижнего тайлов;
- `z` — коэффициент масштабирования;
- `callback` – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе [Формат ответа сервера](#response).

Чтобы менеджер запрашивал данные таким способом, необходимо: 
- в параметре [urlTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md) использовать любые из подстановок: `%t`, `%c`, `%x`, `%y`, `%z` ([подробнее о подстановках](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/loading-object-manager/frontend.md)).

Например:

```javascript
// Создадим менеджер и передадим шаблон URL с подстановками %t и %z (подробнее о подстановках).
// %t – заменяется на последовательность номеров угловых тайлов области. Номера перечисляются через запятую.
// %z – заменяется на уровень масштабирования.
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?tileBounds=%t&z=%z', {
        // Шаблон названия callback-функции, в которую сервер должен обернуть ответ.
        paddingTemplate: 'myCallback_%t_%z'
    });
```

**Рекомендации по размещению данных на сервере**

При таком формате запроса можно настроить в базе составной индекс с ключами x, y и z, где x – номер тайла по X, y – номер тайла по Y и z – коэффициент масштабирования ([подробнее о составных индексах](http://wiki.openstreetmap.org/wiki/QuadTiles)). Тогда можно получить выборку из базы, опираясь на сформированный ключ, аналогично работе с географическими координатами.

**Рекомендации по кэшированию ответа**

В зависимости от действий пользователя на карте размеры запрашиваемых областей будут разными. По этой причине оптимальнее кэшировать выборку из базы потайлово. Поскольку серверу передается параметр tileBounds, содержащий номера первого и последнего тайлов области, нетрудно определить номера остальных тайлов, входящих в эту область. Тогда при запросе данных для некоторой тайловой области нужно «склеить» ответ из данных по каждому тайлу в составе области и отправить ответ на клиент.

Существует множество инструментов, позволяющих реализовать кэширование данных на сервере (например [memcached](http://memcached.org/) или [redis](http://redis.io/)). В качестве ключа кэширования можно использовать параметры `x`, `y`, `z`.

{% endcut %}

{% cut "3. Данные запрашиваются по тайлам по географическим координатам" %}

![](../../_images/bbox_splitRequests_true.png)

Примеры запросов, которые менеджер будет отправлять на сервер:

```httpget
GET https://server.ru/?bbox=55.5587,36.2109,55.7574,36.5625&callback=myCallback_55_5587_36_2109_55_7574_36_5625
GET https://server.ru/?bbox=55.7574,36.2109,55.9552,36.5625&callback=myCallback_55_7574_36_2109_55_9552_36_5625
GET https://server.ru/?bbox=55.3589,36.2109,55.5587,36.5625&callback=myCallback_55_3589_36_2109_55_5587_36_5625 
...
```

где:

- `bbox` – координаты левого нижнего и правого верхнего углов тайла;
- `callback` – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе [Формат ответа сервера](#response).

Чтобы менеджер запрашивал данные таким способом, необходимо: 
- в параметре [urlTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md) использовать подстановку `%b` ([подробнее о подстановках](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/loading-object-manager/frontend.md));
- выставить параметр [splitRequests](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md#param-options.paddingTemplate) в `true`.

Например:

```javascript
// Создадим менеджер, который будет запрашивать данные отдельно по тайлам.
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/?bbox=%b', {
        splitRequests: true,
        paddingTemplate: myCallback_%b
    });
```

**Рекомендации по размещению данных на сервере**

В качестве пространственного индекса базы можно установить поле, содержащее географические координаты углов тайла.

**Рекомендации по кэшированию**

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

{% endcut %}

{% cut "4. Данные запрашиваются по тайлам по номерам этих тайлов" %}

![](../../_images/tile.png)

Пример запросов, которые будет формировать менеджер:

```
GET https://server.ru/?x=622&y=319&z=10&callback=myCallback_x_622_y_319_z_10 
GET https://server.ru/?x=622&y=321&z=10&callback=myCallback_x_622_y_321_z_10  
GET https://server.ru/?x=622&y=322&z=10&callback=myCallback_x_622_y_322_z_10
... 
```

- `x` – номера тайла по оси X;
- `y` – номер тайла по оси Y;
- `z` – коэффициент масштабирования;
- `callback` – имя функции, в которую сервер должен обернуть ответ. Подробнее см. в разделе [Формат ответа сервера](#response).

Чтобы менеджер запрашивал данные таким способом, необходимо: 
- в параметре [urlTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md) использовать любые из подстановок: `%t`, `%c`, `%x`, `%y`, `%z` ([подробнее о подстановках](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/loading-object-manager/frontend.md));
- выставить параметр [splitRequests](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md#param-options.paddingTemplate) в `true`.

Например:

```javascript
// Создадим менеджер, который будет запрашивать данные отдельно по тайлам.
var loadingObjectManager = new ymaps.LoadingObjectManager('http://server.ru/?%c', {
        splitRequests: true,
        // Такой шаблон доступен только при splitRequests=true.
        paddingTemplate: myCallback_%c 
    });
```

{% note info %}

Обратите внимание, подстановка '%c' доступна только при `splitRequests=true`.

{% endnote %}

**Рекомендации по размещению данных на сервере**

При таком формате запроса можно настроить в базе составной индекс с ключами x, y и z ([подробнее о составных индексах](http://wiki.openstreetmap.org/wiki/QuadTiles)).

**Рекомендации по кэшированию**

Когда клиент запрашивает данные потайлово, он формирует конечное число запросов к серверу (карта состоит из конечного числа тайлов). Чтобы при поступлении нового запроса каждый раз не обращаться к базе данных, для каждого запроса можно кэшировать ответ. В качестве ключей кэширования можно установить параметры запроса: `x`, `y`, `z`. Для реализации серверного кэширования можно использовать [memcached](http://memcached.org/) или, например, [redis](http://redis.io/).

{% endcut %}

## Формат ответа сервера {#response-format}

При получении запроса со стороны клиента на сервере необходимо:
1. сформировать [JSON-описание объектов](#json-structure) для запрашиваемой области;
1. обернуть JSON-описание в [callback-функцию](#callback);
1. отправить ответ клиенту.

### Структура JSON-описания объектов {#json-structure}

Описание объектов должно представлять собой GeoJSON-подобную структуру:

```javascript
{
  "type": "FeatureCollection",
  "features": [
      ... 
  ]
}
```

Поле `features` – это массив объектов (меток, кругов, линий и пр.), которые входят в запрашиваемую область. Каждый объект описывается следующими полями:

#|
|| **Поле** | **Тип** | **Описание** ||
|| `type`[*](*star) | String | Поле должно всегда иметь значение "Feature". ||
|| `id`[*](*star) | Number | Уникальный идентификатор объекта. Разработчик должен сформировать идентификаторы объектов самостоятельно.

```javascript
"id": 0
```

||
|| `geometry`[*](*star) | Object | Геометрия объекта. Содержит поля:
- `type` – тип геометрии объекта. Доступные значения: «Point»(метка), «LineString»(линия), «Cicrle»(круг), «Polygon»(многоугольник).
- `coordinates` – координаты объекта. Следует задавать в той последовательности, которая указана в параметре [coordorder](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/dg/concepts/load.md) (если параметр не задан, используется последовательность «широта, долгота»).
- `radius` (только для объекта с типом «Circle») – радиус круга в метрах.

{% cut "Примеры задания геометрии" %}

Для метки:

```json
"geometry": {
    "type": "Point",
    "coordinates": [55.780898, 37.642889]
}
```

Для линии:

```json
"geometry": {
    "type": "LineString",
    "coordinates": [
        [55.780898, 37.642889],
        [55.780898, 37.642889]
    ]
}
```

Для многоугольника:

```json
"geometry": { 
    "type": "Polygon",
    "coordinates": [
        [55.801280971180454, 37.552642822265625],
        [55.81285742969946, 37.518310546875],
        [55.8367712028016, 37.540283203125],
        [55.801280971180454, 37.552642822265625]
    ]
}
```

Для круга:

```json
"geometry": {
    "type": "Circle",
    "coordinates": [55.780898, 37.642889],
    "radius": 1000
}
```

Для кластера:

```json
"geometry": {
    "type": "Point",
    "coordinates": [55.780898, 37.642889]
}
```

{% endcut %}

||
|| `properties` | Object | Свойства объекта (например, содержимое балуна или метки). Список доступных свойств описан в классе [GeoObject](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/GeoObject.md). Кроме того, в свойствах могут быть указаны произвольные поля.

Пример:

```javascript
"properties": {
    "balloonContent": "Текст балуна",
    "clusterCaption": "Метка 1",
    "hintContent": "Текст подсказки",
    "myDescription": "Произвольное описание"
}
```

||
|| `options` | Object | Опции объекта (например, стиль метки или цвет линии). Список доступных опций описан в классе [GeoObject](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/GeoObject.md).

```javascript
"options": {
    "preset": "islands#yellowIcon"
}
```

||
|#

\* Обязательное поле.

{% cut "Пример JSON-описания объектов" %}


```javascript
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": 0,
      "geometry": {
        "type": "Point",
        "coordinates": [55.831903, 37.411961]
      },
      "properties": {
        "balloonContent": "Содержимое балуна",
        "clusterCaption": "Метка 1",
        "hintContent": "Текст подсказки"
      }
    },
    {
      "type": "Feature",
      "id": 1,
      "geometry": {
        "type": "Point",
        "coordinates": [55.763338, 37.565466]
      },
      "properties": {
        "balloonContent": "Содержимое балуна",
        "clusterCaption": "Метка 2",
        "hintContent": "Текст подсказки"
      }
    }
  ]
}
```

{% note alert %}

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

{% endnote %}

{% endcut %}

### Оборачивание JSON-описания в callback {#callback}

Менеджер и сервер обмениваются данными в формате [JSONP](https://ru.wikipedia.org/wiki/JSONP).
 Это означает, что сервер должен возвращать менеджеру JSON-описание, обернутое в
 callback-функцию:

```javascript
callback_function({
  "type": "FeatureCollection",
  "features": [
    ... 
  ]
})
```

Имя функции, в которую сервер должен обернуть ответ, менеджер будет формировать
 автоматически и передавать в запросе в GET-параметре `callback`:

```httpget
/?callback=id_436554526&...
```

При создании менеджера можно задать шаблон, на основе которого менеджер будет формировать
 имена callback-функций. Для этого предназначена опция [paddingTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md#param-options.paddingTemplate):
 
```javascript
// Создание менеджера. 
var loadingObjectManager = new ymaps.LoadingObjectManager('https://server.ru/tile/?%c', {
        // Укажем шаблон для именования callback-функций.
        paddingTemplate: 'myCallback_%c',
        splitRequests: true
    });
```

Тогда для тайла с номером [1,2] и z=5 менеджер отправит запрос по URL:

```httpget
https://server.com/tile/?x=1&y=2&z=5&callback=myCallback_x_1_y_2_z_5
```

Ответ необходимо обернуть следующим образом:

```javascript
myCallback_x_1_y_2_z_5({
  "type": "FeatureCollection",
  "features": [
    ... 
  ]
})
```

Использование параметра [paddingTemplate](https://yandex.com/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/LoadingObjectManager.md#param-options.paddingTemplate) упростит реализацию серверной части, так как для каждого запроса серверу будут заранее известны названия callback-функции. Для каждого тайла JSON-описание можно формировать сразу обернутым в заданную callback-функцию и сохранять это описание в статическом файле.

<!--<section id="splitRequests-false">
  <title>Особенности работы менеджера при splitRequests=false</title>
  <p>Важной особенностью работы менеджера при splitRequests = false является то, что он может запрашивать данные только для прямоугольной области. Однако бывают ситуации, когда нужно подгрузить данные для области, которая имеют форму, отличную от прямоугольной. Пример такой ситуации приведен ниже.</p>
  <p>Менеджер сохраняет загруженные с сервера данные на стороне клиента. По этой причине при небольшом сдвиге карты необходимо подгрузить данные не для всех тайлов из  новой видимой области, а только для некоторых из них. Рисунок ниже иллюстрирует такую ситуацию. Синей рамкой выделены тайлы, для которых данные уже были загружены, а красной — для которых необходимо загрузить. </p>
  <p><image href="../../images/new-viewport.png"/></p>
  <p>В таком случае менеджер разделит исходную фигуру (которая обведена красной рамкой) на две прямоугольные области и для каждой из них отправит серверу отдельный запрос.</p>
  <p><image href="../../images/request-params.png"/></p>
</section>-->
<!--<section>
  <title id="switching-splitRequests">Переключение между режимами</title>
  <p>Иногда требуется настроить менеджер так, чтобы он запрашивал данные у сервера в разных режимах в зависимости от каких-нибудь условий. Ниже приведены рекомендации, как можно изменить режим запроса данных не изменяя при этом струкруту данных на сервере.</p>
  <p>Когда клиент запрашивает у сервера данные по отдельным тайлам (splitRequests = true), он передает серверу номер тайла или его координаты. В таком случае, ответ может быть сформирован динамически из базы данных, либо получен из статических файлов. </p>
  <p>Если в какой-то момент нужно переключить режим, чтобы менеджер запрашивал данные по области видимости, то можно написать на сервере скрипт, который будет переданную область разбивать на отдельные тайлы. Если серверу передан массив, содержащий номера первого и последнего тайлов запрашиваемой области (параметр tileBounds), то нетрудно определить номера остальных тайлов, входящих в эту область. Для каждого отдельного тайла данные можно получить из соответствующих файлов, после чего <q>склеить</q> эти данные в одно JSON-описание. </p>
</section>-->


[*star]: Обязательное поле.