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

# Phân trang API Solana DAS: Truy vấn tập dữ liệu lớn hiệu quả

> Phân trang theo trang và theo khóa cho API Solana DAS. Duyệt qua các tập dữ liệu lớn hiệu quả bằng chiến lược dựa trên con trỏ, phạm vi và truy vấn song song.

## Tổng quan

Các phương thức DAS API trả về tối đa 1.000 bản ghi cho mỗi lần gọi. Để truy xuất thêm, bạn cần phân trang — thực hiện nhiều lệnh gọi và lần lượt duyệt qua các trang dữ liệu. Helius hỗ trợ hai cơ chế: phân trang theo trang và phân trang theo khóa.

Phân trang theo trang là cách đơn giản nhất để bắt đầu. Phân trang theo khóa dành cho người dùng nâng cao cần truy vấn hiệu quả trên các tập dữ liệu lớn (trên 500 nghìn bản ghi).

## Khi nào nên sử dụng

* **Theo trang** — chế độ xem tĩnh, bảng điều khiển và hầu hết các truy vấn hằng ngày. Đơn giản và trực quan.
* **Theo khóa (con trỏ hoặc phạm vi)** — tập dữ liệu lớn (toàn bộ bộ sưu tập, trên 500 nghìn tài sản), khi việc duyệt theo trang trở nên chậm.
* **Theo khóa song song** — lựa chọn nhanh nhất để quét toàn bộ bộ sưu tập bằng cách phân chia phạm vi địa chỉ.

## Tùy chọn sắp xếp

Bạn có thể sắp xếp kết quả theo nhiều trường khác nhau bằng trường `sortBy`:

| Giá trị         | Sắp xếp theo                          | Khuyến nghị? |
| --------------- | ------------------------------------- | ------------ |
| `id`            | ID tài sản ở dạng nhị phân (mặc định) | Có           |
| `created`       | Ngày tạo tài sản                      | Có           |
| `recent_action` | Ngày cập nhật tài sản gần nhất        | Không        |
| `none`          | Không sắp xếp                         | Không        |

Tắt tính năng sắp xếp sẽ cho kết quả nhanh nhất, nhưng do dữ liệu không có thứ tự, bạn có thể nhận được kết quả không nhất quán khi phân trang.

## Phân trang theo trang

Bạn chỉ định số trang và số lượng mục trên mỗi trang. Để chuyển sang trang tiếp theo, hãy tăng số trang. Cách này đơn giản, trực quan và nhanh trong hầu hết trường hợp sử dụng.

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

Khi sử dụng trang, cơ sở dữ liệu phải duyệt qua tất cả các mục cho đến khi đến trang tiếp theo. Ví dụ: nếu bạn yêu cầu trang 100 với kích thước trang là 1.000, cơ sở dữ liệu phải duyệt qua 1 triệu bản ghi đầu tiên trước khi trả về dữ liệu. Vì lý do này, phân trang theo trang không được khuyến nghị cho các tập dữ liệu lớn — phân trang theo khóa phù hợp hơn nhiều với những khối lượng công việc đó.

## Phân trang theo khóa

Bạn xác định các trang bằng cách cung cấp điều kiện để lọc tập dữ liệu. Ví dụ: "lấy tất cả tài sản có ID > X nhưng ID \< Y". Bạn duyệt toàn bộ tập dữ liệu bằng cách thay đổi X hoặc Y trong mỗi lần gọi. Có hai phương thức phân trang theo khóa:

1. **Dựa trên con trỏ** — dễ sử dụng hơn nhưng kém linh hoạt hơn.
2. **Dựa trên phạm vi** — phức tạp hơn nhưng rất linh hoạt.

Phân trang theo khóa chỉ được hỗ trợ khi sắp xếp theo `id`.

### Dựa trên con trỏ

Một truy vấn DAS không có bất kỳ tham số phân trang nào sẽ trả về một con trỏ. Truyền lại con trỏ cho DAS API để tiếp tục từ vị trí đã dừng.

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

Tại thời điểm viết tài liệu này, con trỏ là ID tài sản cuối cùng trong phản hồi; tuy nhiên, thiết kế con trỏ rất linh hoạt và có thể hỗ trợ bất kỳ chuỗi nào.

### Dựa trên phạm vi

Để truy vấn trong một phạm vi, hãy chỉ định `before` và/hoặc `after`. Về cơ bản, truy vấn là "lấy tất cả tài sản sau X nhưng trước Y". Bạn duyệt tập dữ liệu bằng cách cập nhật tham số `before` hoặc `after` trong mỗi lần gọi.

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

## Truy vấn song song bằng khóa (nâng cao)

Người dùng nâng cao truy vấn các tập dữ liệu lớn (ví dụ: toàn bộ bộ sưu tập NFT nén) nên sử dụng phân trang theo khóa để đạt hiệu suất cao. Ví dụ sau minh họa cách truy vấn song song bằng cách phân chia phạm vi địa chỉ Solana và sử dụng các tham số `before`/`after`. Phương thức này nhanh, hiệu quả và an toàn.

<Accordion title="Example">
  Trong ví dụ bên dưới, chúng ta quét toàn bộ bộ sưu tập Tensorian (khoảng 10 nghìn bản ghi). Ví dụ này chia không gian địa chỉ Solana thành 8 phạm vi và quét đồng thời các phạm vi đó. Cách này nhanh hơn nhiều so với các phương pháp khác.

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

## Các bước tiếp theo

<CardGroup cols={3}>
  <Card title="Search Assets" icon="magnifying-glass" href="/docs/vi/das/search">
    Lọc tài sản theo chủ sở hữu, bộ sưu tập và tokenType.
  </Card>

  <Card title="Get Assets (NFTs)" icon="image" href="/docs/vi/das/get-nfts">
    Truy xuất NFT, bộ sưu tập, phiên bản và bằng chứng.
  </Card>

  <Card title="DAS API reference" icon="code" href="/docs/vi/api-reference/das">
    Lược đồ đầy đủ cho mọi phương thức DAS.
  </Card>
</CardGroup>
