> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Пагинация Solana DAS API: эффективные запросы к большим наборам данных

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

## Обзор

Методы DAS API возвращают до 1 000 записей за один вызов. Чтобы получить больше данных, используйте пагинацию — выполняйте несколько вызовов и последовательно обходите страницы данных. Helius поддерживает два механизма: постраничную пагинацию и пагинацию по ключу.

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

## Когда это использовать

* **Постраничная пагинация** — статические представления, панели мониторинга и большинство повседневных запросов. Простой и понятный вариант.
* **Пагинация по ключу (курсор или диапазон)** — большие наборы данных (целые коллекции, более 500 тыс. активов), для которых постраничный обход становится медленным.
* **Параллельная пагинация по ключу** — самый быстрый вариант сканирования всей коллекции путем разделения диапазона адресов.

## Варианты сортировки

Результаты можно сортировать по различным полям с помощью поля `sortBy`:

| Значение | Критерий сортировки | Рекомендуется? |
| - | - | - |
| `id` | ID актива в двоичном формате (по умолчанию) | Да |
| `created` | Дата создания актива | Да |
| `recent_action` | Дата последнего обновления актива | Нет |
| `none` | Без сортировки | Нет |

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

## Постраничная пагинация

Укажите номер страницы и количество элементов на странице. Чтобы перейти к следующей странице, увеличьте номер страницы. Это простой, понятный и быстрый подход для большинства сценариев использования.

<Accordion title="Example">
  ```javascript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      let page = 1;
      let items = [];
      while (true) {
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: {
                      grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                      page: page,
                      limit: 1000,
                      sortBy: { sortBy: 'id', sortDirection: 'asc' },
                  },
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results from page ${page}`);
              items.push(...result.items);
              page += 1;
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

При использовании страниц базе данных необходимо обходить все элементы, пока она не достигнет следующей страницы. Например, если запросить страницу 100 с размером страницы 1 000, база данных должна пройти первые 1 млн записей, прежде чем вернуть данные. Поэтому постраничная пагинация не рекомендуется для больших наборов данных — пагинация по ключу гораздо лучше подходит для таких нагрузок.

## Пагинация по ключу

Для определения страниц задайте условия, фильтрующие набор данных. Например: «Получить все активы с ID > X, но с ID \< Y». Чтобы обойти весь набор данных, изменяйте X или Y при каждом вызове. Существует два метода пагинации по ключу:

1. **На основе курсора** — проще в использовании, но менее гибкий.
2. **На основе диапазона** — более сложный, но очень гибкий.

Пагинация по ключу поддерживается только при сортировке по `id`.

### На основе курсора

Запрос DAS без параметров пагинации возвращает курсор. Передайте курсор обратно в DAS API, чтобы продолжить с места остановки.

<Accordion title="Example">
  ```typescript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      let items = [];
      let cursor;
      while (true) {
          let params = {
              grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
              limit: 1000,
              sortBy: { sortBy: 'id', sortDirection: 'asc' },
          } as any;
          if (cursor != undefined) {
              params.cursor = cursor;
          }
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: params,
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results for cursor ${cursor}`);
              cursor = result.cursor;
              items.push(...result.items);
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

На момент написания документации курсор представляет собой ID последнего актива в ответе. Однако структура курсора допускает использование любой строки.

### На основе диапазона

Чтобы выполнить запрос по диапазону, укажите `before` и/или `after`. По сути, запрос означает: «Получить все активы после X, но до Y». Чтобы обойти набор данных, обновляйте параметр `before` или `after` при каждом вызове.

<Accordion title="Example">
  ```javascript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      // Two NFTs from the Tensorian collection.
      // The "start" item has a lower asset ID (in binary) than the "end" item.
      // We will traverse in ascending order.
      let start = '6CeKtAYX5USSvPCQicwFsvN4jQSHNxQuFrX2bimWrNey';
      let end = 'CzTP4fUbdfgKzwE6T94hsYV7NWf1SzuCCsmJ6RP1xsDw';
      let sortDirection = 'asc';
      let after = start;
      let before = end;
      let items = [];

      while (true) {
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: {
                      grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                      limit: 1000,
                      after: after,
                      before: before,
                      sortBy: { sortBy: 'id', sortDirection: sortDirection },
                  },
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results with (after: ${after}, before: ${before})`);
              after = result.items[result.items.length - 1].id;
              items.push(...result.items);
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

## Параллельные запросы с пагинацией по ключу (для опытных пользователей)

Для повышения производительности опытным пользователям, выполняющим запросы к большим наборам данных (например, к целым коллекциям сжатых NFT), следует использовать пагинацию по ключу. В следующем примере показано, как выполнять запросы параллельно, разделяя диапазон адресов Solana и используя параметры `before`/`after`. Этот метод быстрый, эффективный и безопасный.

<Accordion title="Example">
  В приведенном ниже примере сканируется вся коллекция Tensorian (около 10 тыс. записей). Пространство адресов Solana разделяется на 8 диапазонов, которые сканируются параллельно. Это гораздо быстрее других подходов.

  ```typescript theme={"system"}
  import base58 from 'bs58';

  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const main = async () => {
      let numParitions = 8;
      let partitons = partitionAddressRange(numParitions);
      let promises = [];
      for (const [i, partition] of partitons.entries()) {
          let [s, e] = partition;
          let start = bs58.encode(s);
          let end = bs58.encode(e);
          console.log(`Parition: ${i}, Start: ${start}, End: ${end}`);

          let promise: Promise<number> = new Promise(async (resolve, reject) => {
              let current = start;
              let totalForPartition = 0;
              while (true) {
                  const response = await fetch(url, {
                      method: 'POST',
                      headers: {
                          'Content-Type': 'application/json',
                      },
                      body: JSON.stringify({
                          jsonrpc: '2.0',
                          id: 'my-id',
                          method: 'searchAssets',
                          params: {
                              grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                              limit: 1000,
                              after: current,
                              before: end,
                              sortBy: { sortBy: 'id', sortDirection: 'asc' },
                          },
                      }),
                  });
                  const { result } = await response.json();
                  totalForPartition += result.items.length;
                  console.log(`Found ${totalForPartition} total items in parition ${i}`);
                  if (result.items.length == 0) {
                      break;
                  } else {
                      current = result.items[result.items.length - 1].id;
                  }
              }
              resolve(totalForPartition);
          });
          promises.push(promise);
      }
      let results = await Promise.all(promises);
      let total = results.reduce((a, b) => a + b, 0);
      console.log(`Got ${total} total items`);
  };

  // Function to convert a BigInt to a byte array
  function bigIntToByteArray(bigInt: bigint): Uint8Array {
      const bytes = [];
      let remainder = bigInt;
      while (remainder > 0n) {
          // use 0n for bigint literal
          bytes.unshift(Number(remainder & 0xffn));
          remainder >>= 8n;
      }
      while (bytes.length < 32) bytes.unshift(0); // pad with zeros to get 32 bytes
      return new Uint8Array(bytes);
  }

  function partitionAddressRange(numPartitions: number) {
      let N = BigInt(numPartitions);

      // Largest and smallest Solana addresses in integer form.
      // Solana addresses are 32 byte arrays.
      const start = 0n;
      const end = 2n ** 256n - 1n;

      // Calculate the number of partitions and partition size
      const range = end - start;
      const partitionSize = range / N;

      // Calculate partition ranges
      const partitions: Uint8Array[][] = [];
      for (let i = 0n; i < N; i++) {
          const s = start + i * partitionSize;
          const e = i === N - 1n ? end : s + partitionSize;
          partitions.push([bigIntToByteArray(s), bigIntToByteArray(e)]);
      }

      return partitions;
  }

  main();
  ```
</Accordion>

## Дальнейшие действия

<CardGroup cols={3}>
  <Card title="Search Assets" icon="magnifying-glass" href="/docs/ru/das/search">
    Фильтруйте активы по владельцу, коллекции и tokenType.
  </Card>

  <Card title="Get Assets (NFTs)" icon="image" href="/docs/ru/das/get-nfts">
    Получайте NFT, коллекции, издания и доказательства.
  </Card>

  <Card title="DAS API reference" icon="code" href="/docs/ru/api-reference/das">
    Полные схемы для каждого метода DAS.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.