> ## 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.

# Paginación de la API DAS de Solana: consultas eficientes de grandes conjuntos de datos

> Paginación por páginas y por conjunto de claves para la API DAS de Solana. Recorre grandes conjuntos de datos de forma eficiente con estrategias basadas en cursores y rangos, y consultas en paralelo.

## Descripción general

Los métodos de la API DAS devuelven hasta 1,000 registros por llamada. Para recuperar más, debes paginar: hacer varias llamadas y recorrer páginas de datos. Helius admite dos mecanismos: paginación por páginas y por conjunto de claves.

La paginación por páginas es la forma más sencilla de comenzar. La paginación por conjunto de claves está dirigida a usuarios avanzados que necesitan consultar grandes conjuntos de datos (más de 500 mil) de forma eficiente.

## Cuándo usar esto

* **Por páginas** — vistas estáticas, paneles y la mayoría de las consultas cotidianas. Fácil e intuitiva.
* **Por conjunto de claves (cursor o rango)** — grandes conjuntos de datos (colecciones completas, más de 500 mil activos) en los que el recorrido por páginas se vuelve lento.
* **Por conjunto de claves en paralelo** — la opción más rápida para analizar una colección completa mediante la partición del rango de direcciones.

## Opciones de ordenamiento

Puedes ordenar los resultados por diferentes campos mediante el campo `sortBy`:

| Valor           | Ordena por                                        | ¿Recomendado? |
| --------------- | ------------------------------------------------- | ------------- |
| `id`            | ID del activo en formato binario (predeterminado) | Sí            |
| `created`       | Fecha de creación del activo                      | Sí            |
| `recent_action` | Fecha de la última actualización del activo       | No            |
| `none`          | Sin ordenamiento                                  | No            |

Desactivar el ordenamiento produce los resultados más rápidos, pero como los datos no están ordenados, podrías obtener resultados inconsistentes al paginar.

## Paginación por páginas

Especifica el número de página y la cantidad de elementos por página. Para avanzar a la página siguiente, incrementa el número de página. Este método es fácil, intuitivo y rápido para la mayoría de los casos de uso.

<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>

El uso de páginas requiere que la base de datos recorra todos los elementos hasta llegar a la página siguiente. Por ejemplo, si solicitas la página 100 con un tamaño de página de 1,000, la base de datos debe recorrer el primer millón de registros antes de devolver tus datos. Por este motivo, no se recomienda la paginación por páginas para conjuntos de datos grandes; la paginación por conjunto de claves es mucho más adecuada para esas cargas de trabajo.

## Paginación por conjunto de claves

Defines las páginas mediante condiciones que filtran el conjunto de datos. Por ejemplo: «obtén todos los activos con un ID > X, pero con un ID \< Y». Recorres todo el conjunto de datos modificando X o Y en cada llamada. Existen dos métodos de paginación por conjunto de claves:

1. **Basada en cursor** — más fácil de usar, pero menos flexible.
2. **Basada en rango** — más compleja, pero muy flexible.

La paginación por conjunto de claves solo es compatible cuando se ordena por `id`.

### Basada en cursor

Una consulta de DAS sin parámetros de paginación devuelve un cursor. Envía el cursor de vuelta a la API DAS para continuar desde donde te quedaste.

<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>

Al momento de redactar esta documentación, el cursor es el ID del último activo de la respuesta; sin embargo, el diseño del cursor es flexible y admite cualquier cadena.

### Basada en rango

Para consultar un rango, especifica `before` y/o `after`. En esencia, la consulta indica: «obtén todos los activos posteriores a X, pero anteriores a Y». Recorres el conjunto de datos actualizando el parámetro `before` o `after` en cada llamada.

<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>

## Consultas en paralelo con conjuntos de claves (avanzado)

Para obtener un buen rendimiento, los usuarios avanzados que consultan grandes conjuntos de datos (por ejemplo, colecciones completas de NFT comprimidos) deben usar la paginación por conjunto de claves. El siguiente ejemplo muestra cómo realizar consultas en paralelo mediante la partición del rango de direcciones de Solana y el uso de los parámetros `before`/`after`. Este método es rápido, eficiente y seguro.

<Accordion title="Example">
  En el siguiente ejemplo, analizamos toda la colección Tensorian (unos 10 mil registros). El proceso divide el espacio de direcciones de Solana en 8 rangos y los analiza simultáneamente. Esto es mucho más rápido que los otros enfoques.

  ```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>

## Próximos pasos

<CardGroup cols={3}>
  <Card title="Search Assets" icon="magnifying-glass" href="/docs/es/das/search">
    Filtra activos por propietario, colección y tokenType.
  </Card>

  <Card title="Get Assets (NFTs)" icon="image" href="/docs/es/das/get-nfts">
    Recupera NFT, colecciones, ediciones y pruebas.
  </Card>

  <Card title="DAS API reference" icon="code" href="/docs/es/api-reference/das">
    Esquemas completos para cada método de DAS.
  </Card>
</CardGroup>
