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

# Paginasi Solana DAS API: Kueri Dataset Besar secara Efisien

> Paginasi berbasis halaman dan keyset untuk Solana DAS API. Iterasikan dataset besar secara efisien dengan strategi berbasis kursor dan rentang serta kueri paralel.

## Ringkasan

Metode DAS API mengembalikan hingga 1.000 rekaman per panggilan. Untuk mengambil lebih banyak rekaman, Anda perlu melakukan paginasi — membuat beberapa panggilan dan menelusuri halaman-halaman data. Helius mendukung dua mekanisme: paginasi berbasis halaman dan keyset.

Paginasi berbasis halaman adalah cara termudah untuk memulai. Paginasi keyset ditujukan bagi pengguna tingkat lanjut yang perlu membuat kueri secara efisien di seluruh dataset besar (500 ribu+).

## Kapan menggunakannya

* **Berbasis halaman** — tampilan statis, dasbor, dan sebagian besar kueri sehari-hari. Mudah dan intuitif.
* **Keyset (kursor atau rentang)** — dataset besar (seluruh koleksi, 500 ribu+ aset) ketika penelusuran berbasis halaman menjadi lambat.
* **Keyset paralel** — opsi tercepat untuk memindai seluruh koleksi dengan mempartisi rentang alamat.

## Opsi pengurutan

Anda dapat mengurutkan hasil berdasarkan berbagai bidang menggunakan bidang `sortBy`:

| Nilai           | Diurutkan berdasarkan                | Direkomendasikan? |
| --------------- | ------------------------------------ | ----------------- |
| `id`            | ID aset dalam format biner (default) | Ya                |
| `created`       | Tanggal aset dibuat                  | Ya                |
| `recent_action` | Tanggal terakhir aset diperbarui     | Tidak             |
| `none`          | Tanpa pengurutan                     | Tidak             |

Menonaktifkan pengurutan memberikan hasil tercepat, tetapi karena data tidak berurutan, Anda mungkin mendapatkan hasil yang tidak konsisten saat melakukan paginasi.

## Paginasi berbasis halaman

Anda menentukan nomor halaman dan jumlah item per halaman. Untuk berpindah ke halaman berikutnya, naikkan nomor halaman. Cara ini mudah, intuitif, dan cepat untuk sebagian besar kasus penggunaan.

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

Penggunaan halaman mengharuskan basis data menelusuri semua item hingga mencapai halaman berikutnya. Misalnya, jika Anda meminta halaman ke-100 dengan ukuran halaman 1.000, basis data harus menelusuri 1 juta rekaman pertama sebelum mengembalikan data Anda. Karena itu, paginasi berbasis halaman tidak direkomendasikan untuk dataset besar — paginasi keyset jauh lebih cocok untuk beban kerja tersebut.

## Paginasi keyset

Anda menentukan halaman dengan menyediakan kondisi yang memfilter dataset. Misalnya, "ambil semua aset dengan ID > X tetapi ID \< Y." Anda menelusuri seluruh dataset dengan mengubah X atau Y pada setiap panggilan. Ada dua metode paginasi keyset:

1. **Berbasis kursor** — lebih mudah digunakan, tetapi kurang fleksibel.
2. **Berbasis rentang** — lebih kompleks, tetapi sangat fleksibel.

Paginasi keyset hanya didukung saat mengurutkan berdasarkan `id`.

### Berbasis kursor

Kueri DAS tanpa parameter paginasi akan mengembalikan kursor. Kirimkan kembali kursor tersebut ke DAS API untuk melanjutkan dari posisi terakhir Anda.

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

Pada saat dokumentasi ini ditulis, kursor adalah ID aset terakhir dalam respons. Namun, desain kursor bersifat fleksibel dan dapat mendukung string apa pun.

### Berbasis rentang

Untuk membuat kueri dalam suatu rentang, tentukan `before` dan/atau `after`. Pada dasarnya, kueri tersebut berarti "ambil semua aset setelah X tetapi sebelum Y." Anda menelusuri dataset dengan memperbarui parameter `before` atau `after` pada setiap panggilan.

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

## Kueri paralel dengan keyset (tingkat lanjut)

Pengguna tingkat lanjut yang membuat kueri pada dataset besar (misalnya, seluruh koleksi NFT terkompresi) sebaiknya menggunakan paginasi berbasis keyset untuk meningkatkan performa. Contoh berikut menunjukkan cara membuat kueri secara paralel dengan mempartisi rentang alamat Solana dan menggunakan parameter `before`/`after`. Metode ini cepat, efisien, dan aman.

<Accordion title="Example">
  Dalam contoh di bawah ini, kami memindai seluruh koleksi Tensorian (\~10 ribu rekaman). Contoh ini mempartisi ruang alamat Solana menjadi 8 rentang dan memindai rentang-rentang tersebut secara bersamaan. Cara ini jauh lebih cepat daripada pendekatan lainnya.

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

## Langkah berikutnya

<CardGroup cols={3}>
  <Card title="Search Assets" icon="magnifying-glass" href="/docs/id/das/search">
    Filter aset berdasarkan pemilik, koleksi, dan tokenType.
  </Card>

  <Card title="Get Assets (NFTs)" icon="image" href="/docs/id/das/get-nfts">
    Ambil NFT, koleksi, edisi, dan bukti.
  </Card>

  <Card title="DAS API reference" icon="code" href="/docs/id/api-reference/das">
    Skema lengkap untuk setiap metode DAS.
  </Card>
</CardGroup>
