---
url: https://docs.juniper.bot/message-templates/persistence/guild-indexes.md
description: Руководство по хранению данных в индексах сервера
---

[Число]: /message-templates/types/index#literals

[Строка]: /message-templates/types/index#literals

[Логический]: /message-templates/types/index#literals

[Список]: /message-templates/types/index#lists

[Карта]: /message-templates/types/index#maps

[DateTime]: /message-templates/types/index#datetime

[TwitchChannel]: /message-templates/types/subscriptions/twitch#twitch-channel

[TwitchStream]: /message-templates/types/subscriptions/twitch#twitch-stream

[TwitchGame]: /message-templates/types/subscriptions/twitch#twitch-game

[YouTubeChannel]: /message-templates/types/subscriptions/youtube#youtube-channel

[YouTubeVideo]: /message-templates/types/subscriptions/youtube#youtube-video

[VkWallPost]: /message-templates/types/subscriptions/vk#vkwallpost

[Rank]: /message-templates/types/discord/rank

[Guild]: /message-templates/types/discord/guild

[Member]: /message-templates/types/discord/member

[Role]: /message-templates/types/discord/role

[Message]: /message-templates/types/discord/message

[Attachment]: /message-templates/types/discord/attachment

[Embed]: /message-templates/types/discord/embed

[Activity]: /message-templates/types/discord/activity

[MemberVoiceState]: /message-templates/types/discord/member-voice-state

[MemberPrimaryGuild]: /message-templates/types/discord/member-primary-guild

[MenuBuilder]: /message-templates/types/discord/menu-builder

[UserFlag]: /message-templates/types/discord/user-flag

[Permission]: /message-templates/types/discord/permission

[Category]: /message-templates/types/discord/category

[TextChannel]: /message-templates/types/discord/text-channel

[VoiceChannel]: /message-templates/types/discord/voice-channel

[NewsChannel]: /message-templates/types/discord/news-channel

[StageChannel]: /message-templates/types/discord/stage-channel

[ForumChannel]: /message-templates/types/discord/forum-channel

[MediaChannel]: /message-templates/types/discord/media-channel

[ThreadChannel]: /message-templates/types/discord/thread-channel

[Page]: /message-templates/types/storage/page

[GuildIndex]: /message-templates/types/storage/guild-index

[GuildIndexEntry]: /message-templates/types/storage/guild-index-entry

[GuildIndexes]: /message-templates/types/storage/guild-indexes

[MemberAttribute]: /message-templates/types/storage/member-attribute

[MemberAttributes]: /message-templates/types/storage/member-attributes

[Arguments]: /message-templates/types/custom-commands/arguments

[Parameters]: /message-templates/types/custom-commands/parameters

[Component]: /message-templates/types/custom-commands/component

[Modal]: /message-templates/types/custom-commands/modal

# Индексы сервера { #guild-indexes }

Индексы сервера — особое хранилище данных, предназначенное для хранения большого массива отсортированных данных.
Данный тип хранилища применим для создания рейтингов (топов) чего-либо, историй заметок участников или любых других
сортируемых записей.

Это хранилище состоит из двух частей: [Индексы](../types/storage/guild-index) и [Записи](../types/storage/guild-index-entry).

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

Индексы представлены методом [`getIndex`](../types/discord/guild#method-getindex) и свойством
[`indexes`](../types/storage/guild-indexes) у типа \[Guild].

::: warning Внимание
В рамках выполнения одного шаблона сообщения допускается обращение максимум к 2 разным индексам сервера и
запрос/обновление до двух записей любого индекса.
:::

## Сохранение данных { #saving }

Для сохранения каких-либо данных в индексы можно использовать следующие конструкции:

::: tabs

\== Метод | mdi-code-parentheses

```template
{% do guild.getIndex('myIndex').get('entryKey').update(123) %}
```

Здесь используются:

1. Метод [`getIndex`](../types/discord/guild#method-getindex) у типа \[Guild] для получения индекса с названием `myIndex`;
2. Метод [`get`](../types/storage/guild-index#method-get) у типа \[GuildIndex] для получения записи этого индекса с ключом `entryKey`;
3. Метод [`update`](../types/storage/guild-index-entry#method-update) у типа \[GuildIndexEntry] для сохранения значения `123` в эту запись.

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{% do guild.indexes.myIndex.entryKey.update(123) %}
```

Здесь используется метод [`update`](../types/storage/guild-index-entry#method-update) у типа \[GuildIndexEntry] для сохранения значения `123` в запись `entryKey` индекса `myIndex`.

:::

Также можно обновить сразу до двух записей в индексе одновременно, используя метод [`update`](../types/storage/guild-index#method-update) у типа \[GuildIndex]:

::: tabs

\== Метод | mdi-code-parentheses

```template
{% do guild.getIndex('myIndex').update({ entryKey1: 123, entryKey2: 321 }) %}
```

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{% do guild.indexes.myIndex.update({ entryKey1: 123, entryKey2: 321 }) %}
```

:::

Вы можете увеличить или уменьшить значение записи на указанное число, используя методы
[`increment`](../types/storage/guild-index-entry#method-increment) и [`decrement`](../types/storage/guild-index-entry#method-decrement):

::: tabs

\== Метод | mdi-code-parentheses

Увеличение значения:

```template
{% do guild.getIndex('myIndex').get('entryKey').increment(1) %}
```

Уменьшение значения:

```template
{% do guild.getIndex('myIndex').get('entryKey').decrement(1) %}
```

\== Свойство | mdi-alphabet-latin

Данные способы доступны только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

Увеличение значения:

```template
{% do guild.indexes.myIndex.entryKey.increment(1) %}
```

Уменьшение значения:

```template
{% do guild.indexes.myIndex.entryKey.decrement(1) %}
```

:::

## Запрос данных { #accessing }

### Конкретное значение { #accessing-value }

Индексы и их записи хранятся бессрочно и доступ к ним можно получить следующими способами:

::: tabs

\== Метод | mdi-code-parentheses

```template
{{ guild.getIndex('myIndex').get('entryKey').value }}
```

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{{ guild.indexes.myIndex.entryKey.value }}
```

:::

### Страница { #accessing-page }

Самое интересное и то, ради чего индексы создавались — запрос страницы записей индекса, отсортированные по их значению.
Для этого используется метод [`getPageOf`](../types/storage/guild-index#method-getpageof):

::: tabs

\== Метод | mdi-code-parentheses

```template
{% set page = guild.getIndex('myIndex').getPageOf(0, 10, 'DESC') %}
```

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{% set page = guild.indexes.myIndex.getPageOf(0, 10, 'DESC') %}
```

:::

Таким образом вы получите объект страницы с типом \[Page], содержащий в себе список записей \[GuildIndexEntry], а также
дополнительную информацию, позволяющую реализовать даже постраничную навигацию!

::: details Пример постраничной навигации

Следующий код демонстрирует пример топа балансов с постраничной навигацией.

Вам необходимо создать действие [отправки сообщения](../../cmd/custom/actions/message) в режиме текста, поставить в нём
галочку "Отредактировать сообщение компонента" и вставить следующий код, заменив UUID действия в первой строчке на свой.

```template
{% set actionId = 'ae04dfed-e19c-49d3-84fc-b05cec59976e' %}
{% set targetMember = arguments.targetMember %}

{% if targetMember and not component %}
  {% set newBalance = random(1000) %}
  
  {# Получаем запись баланса для участника из индекса балансов #}
  {% set balanceEntry = guild.indexes.balances.get(targetMember.id) %}
  {# Обновляем баланс на новый #}
  {% do balanceEntry.update(newBalance) %}
  
  Баланс {{ targetMember }} установлен на {{ newBalance }}!
{% else %}

  {# Вычисляем номер запрашиваеой страницы #}
  {% set wasLast = parameters.get('page.isLast') %}
  {% set pageNum = (parameters.get('page.number')) ?: 0 %}
  {% if component.id == 'next_page' and not wasLast %}
    {% set pageNum += 1 %}
  {% elseif component.id == 'prev_page' and pageNum > 0 %}
    {% set pageNum -= 1 %}
  {% endif %}

  {# Получаем страницу из индекса, сохраняя в параметры данные для возможности вычисления номера новой страницы #}
  {% set page = guild.indexes.balances.getPageOf(pageNum, 2, 'DESC') %}
  {% do parameters.store('page.number', page.number) %}
  {% do parameters.store('page.isLast', page.isLast) %}
  {% set isEmpty = page.totalPages <= 0 %}
  
  {% if not isEmpty -%}
    {# Если в индексе есть данные, показываем содержимое страницы #}
    Страница {{ page.number + 1 }} из {{ page.totalPages }} (всего {{ page.totalElements }} элементов)
    {% for entry in page %}
      {% set number = loop.index + page.number * page.size -%}
      {{ number }}. <@{{ entry.key }}>: {{ entry.value -}}
    {% endfor %}
  {%- else -%}
    Записи отсутствуют
  {%- endif %}

  {# Отобразим кнопки пагинации #}
  {% set pageLabel = (page.number + 1) ~ ' / ' ~ page.totalPages %}
  {% do button('PRIMARY', 'prev_page', null, '⬅️', actionId, isEmpty or page.isFirst) %}
  {% do button('SECONDARY', 'current_page', pageLabel, null, actionId, true) %}
  {% do button('PRIMARY', 'next_page', null, '➡️', actionId, isEmpty or page.isLast) %}
{% endif %}
```

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

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

::: warning Внимание
В рамках выполнения одного шаблона сообщения допускается запрос только одной страницы одного любого индекса, в которой
может быть до 25 записей.
:::

## Очистка данных { #clearing }

Для очистки записи индекса следует использовать метод [`clear`](../types/storage/guild-index-entry#method-clear) у типа \[GuildIndexEntry]:

::: tabs

\== Метод | mdi-code-parentheses

```template
{% do guild.getIndex('myIndex').get('entryKey').clear() %}
```

Здесь используются:

1. Метод [`getIndex`](../types/discord/guild#method-getindex) у типа \[Guild] для получения индекса с названием `myIndex`;
2. Метод [`get`](../types/storage/guild-index#method-get) у типа \[GuildIndex] для получения записи этого индекса с ключом `entryKey`;
3. Метод [`clear`](../types/storage/guild-index-entry#method-clear) у типа \[GuildIndexEntry] для очистки записи.

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{% do guild.indexes.myIndex.entryKey.clear() %}
```

Здесь используется метод [`clear`](../types/storage/guild-index-entry#method-clear) у типа \[GuildIndexEntry] для очистки записи `entryKey` индекса `myIndex`.

:::

Если вы хотите очистить вообще все записи конкретного индекса, используйте метод [`clearAll`](../types/storage/guild-index#method-clearall) у типа \[GuildIndex]:

::: tabs

\== Метод | mdi-code-parentheses

```template
{% do guild.getIndex('myIndex').clearAll() %}
```

\== Свойство | mdi-alphabet-latin

Данный способ доступен только если название индекса и ключ записи являются корректными [идентификаторами](../advanced/expressions#identifiers):

```template
{% do guild.indexes.myIndex.clearAll() %}
```

:::
