---
url: https://docs.juniper.bot/en/message-templates/persistence/guild-indexes.md
description: Data Persistence guide for Guild Indexes
---

[Number]: /en/message-templates/types/index#literals

[String]: /en/message-templates/types/index#literals

[Boolean]: /en/message-templates/types/index#literals

[List]: /en/message-templates/types/index#lists

[Map]: /en/message-templates/types/index#maps

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# Guild Indexes { #guild-indexes }

Guild Indexes are a special data storage designed for storing large arrays of sorted data.
This type of storage is suitable for creating ratings (top lists), user note histories, or any other sortable records.

This storage consists of two parts: [Indexes](../types/storage/guild-index) и [Entries](../types/storage/guild-index-entry).

An index is a group of entries. A guild can have an unlimited amount of such indexes (groups) with unique names, each
of then can contain an unlimited amount of entries with unique keys and their corresponding numerical values.

Indexes are represented by [`getIndex`](../types/discord/guild#method-getindex) method and
[`indexes`](../types/storage/guild-indexes) property of \[Guild] data type.

::: warning
You can only access up to 2 guild indexes in single message template and update up to two entries of any index.
:::

## Saving Data { #saving }

In order to save any data into indexes, you should use following construct:

::: tabs

\== Method | mdi-code-parentheses

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

We are using:

1. [`getIndex`](../types/discord/guild#method-getindex) method of \[Guild] data type to get an index with `myIndex` name;
2. [`get`](../types/storage/guild-index#method-get) method  of \[GuildIndex] data type to get an entry with key `entryKey`;
3. [`update`](../types/storage/guild-index-entry#method-update) method of \[GuildIndexEntry] data type to save `123` value into this entry.

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

We are using [`update`](../types/storage/guild-index-entry#method-update) method of \[GuildIndexEntry] data type to
save `123` value into `entryKey` entry of `myIndex` index.

:::

You can also batch update up to two entries with a single call of [`update`](../types/storage/guild-index#method-update) method of \[GuildIndex]:

::: tabs

\== Method | mdi-code-parentheses

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

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

:::

You can increment or decrement entry value by specified amount using
[`increment`](../types/storage/guild-index-entry#method-increment) and
[`decrement`](../types/storage/guild-index-entry#method-decrement) methods:

::: tabs

\== Method | mdi-code-parentheses

Incrementing value:

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

Decrementing value:

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

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

Incrementing value:

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

Decrementing value:

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

:::

## Accessing Data { #accessing }

### Single Value { #accessing-value }

Indexes and their entries are stored indefinitely and can be accessed as follows:

::: tabs

\== Method | mdi-code-parentheses

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

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

:::

### Page { #accessing-page }

This is the most interesting and the main reason why indexes exist — requesting an entire page of index entries sorted
by their values. You can use [`getPageOf`](../types/storage/guild-index#method-getpageof) method to do exactly that:

::: tabs

\== Method | mdi-code-parentheses

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

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

:::

This way you will get a \[Page] object containing the list of \[GuildIndexEntry] entries, plus some additional information
that you can use to build a working pagination!

::: details Pagination example

The following code shows an example of a balance top with pagination navigation.

You need to create a [Send Message](../../cmd/custom/actions/message) action in text mode, check the
"Edit Component Message" box, and paste the following code, replacing the action UUID in the first line with your own.

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

{% if targetMember and not component %}
  {% set newBalance = random(1000) %}
  
  {# Requesting balance entry for member from balances index #}
  {% set balanceEntry = guild.indexes.balances.get(targetMember.id) %}
  {# Updating the balance #}
  {% do balanceEntry.update(newBalance) %}
  
  Balance of {{ targetMember }} has been set to {{ newBalance }}!
{% else %}

  {# Calculating requested page number #}
  {% 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 %}

  {# Requesting the page from the index, saving some if its data that will be used to calculate next page number #}
  {% 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 -%}
    {# If we have any data in the index, show page content #}
    Page {{ page.number + 1 }} of {{ page.totalPages }} (total {{ page.totalElements }} entries)
    {% for entry in page %}
      {% set number = loop.index + page.number * page.size -%}
      {{ number }}. <@{{ entry.key }}>: {{ entry.value -}}
    {% endfor %}
  {%- else -%}
    No records
  {%- endif %}

  {# Show pagination buttons #}
  {% 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 %}
```

Running a command with this template will send a message with a paginated list of balances from the index.

Initially, there are no entries in the index. but you can run this command mentioning different members to set them random balances.
Then run the command again without mentioning anyone to get an example of working pagination.

:::

::: warning
You can only request a single page of any index in single message template, containing up to 25 entries.
:::

## Clearing Data { #clearing }

In order to clear index entry use [`clear`](../types/storage/guild-index-entry#method-clear) method of \[GuildIndexEntry] data type:

::: tabs

\== Method | mdi-code-parentheses

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

We are using:

1. [`getIndex`](../types/discord/guild#method-getindex) method of \[Guild] data type to get an index with `myIndex` name;
2. [`get`](../types/storage/guild-index#method-get) method  of \[GuildIndex] data type to get an entry with key `entryKey`;
3. [`clear`](../types/storage/guild-index-entry#method-clear) method of \[GuildIndexEntry] data type to clear this entry.

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

We are using [`clear`](../types/storage/guild-index-entry#method-clear) method of \[GuildIndexEntry] data type to clear
`entryKey` entry of `myIndex` index.

:::

If you want to clear every single entry of the index from the server, use
[`clearAll`](../types/storage/guild-index#method-clearall) method of \[GuildIndex] data type:

::: tabs

\== Method | mdi-code-parentheses

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

\== Property | mdi-alphabet-latin

This option is only available if index name and entry key are valid [identifiers](../advanced/expressions#identifiers):

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

:::
