Paginated Search
In this guide, we will explain how to perform paginated search queries using the FHIR specification. Specifically, we will discuss using the _count
parameter to set the page size, the _offset
parameter to set the page offset, and the Bundle.link
field to retrieve subsequent pages.
Setting the page size with the _count
parameter
To set the number of items returned per page, use the _count
query parameter. In the Medplum API, the default page size is 20, and the maximum allowed page size is 1000.
Here's an example query that sets the page size to 50:
- TypeScript
- cURL
await medplum.searchResources('Patient', { _count: '50' });
curl https://api.medplum.com/Patient?_count=50
In this example, the search will return up to 50 Patient resources per page.
Setting the page offset with the _offset
parameter
To set the page offset, or the starting point of the search results, use the _offset
query parameter. This allows you to skip a certain number of items before starting to return results.
Here's an example query that sets the page offset to 30:
- TypeScript
- cURL
await medplum.searchResources('Patient', { _count: '50', _offset: '30' });
curl https://api.medplum.com/Patient?_count=50&_offset=30
In this example, the search will return up to 50 Patient resources per page, starting from the 31st item in the result set.
Getting the total number of results with _total
To include the total count of matching resources in the search response, you need to use the _total
parameter in your search query. This information is particularly useful for pagination and understanding the scope of the data you are dealing with.
The _total
parameter can have three values: accurate
, estimate
, and none
.
none (Default) | No total is returned |
estimate | Tells the Medplum server that you are willing to accept an approximate count. This is usually faster than the accurate option as it may use database statistics or other methods for estimating the total number without scanning the entire dataset. This option is particularly useful when you need a rough idea of the number of resources without requiring precision. |
accurate | The Medplum server will perform additional processing to calculate the exact number of resources that match the search criteria. This can be more time-consuming, especially for large datasets, but you will receive a precise count. Use this option when an exact number is crucial for your use case. |
By default, searches the response do not include totals. Choosing between accurate
and estimate
depends on your specific requirements. For large datasets, using estimate
can significantly improve response times, but at the cost of precision.
Example Query
Here is an example of how to use the _total
parameter in a search query:
- TypeScript
- cURL
await medplum.search('Patient', { name: 'Smith', _total: 'accurate' });
curl https://api.medplum.com/fhir/R4/Patient?name=smith&_total=accurate
This query will search for patients with the name "smith" and will return a Bundle with the accurate total number of matching resources included.
const response: Bundle = {
resourceType: 'Bundle',
id: 'bundle-id',
type: 'searchset',
total: 15,
entry: [
{
fullUrl: 'http://example.com/base/Patient/1',
resource: {
resourceType: 'Patient',
// ...
},
},
{
fullUrl: 'http://example.com/base/Patient/2',
resource: {
resourceType: 'Patient',
// ...
},
},
// ...
],
// ...
};
Navigating pages with the Bundle.link
element
When you perform a paginated search, the response will be a Bundle
resource containing a list of resources matching the query. The Bundle
resource will also have a link
field containing navigation links to help you traverse through the search results.
The Bundle.link
field will include the following relations:
self
: The URL of the current search results page.first
: The URL of the first page of search results.previous
: The URL of the previous page of search results (if applicable).next
: The URL of the next page of search results (if applicable).
Here's an example of how the Bundle.link field may look :
'link': [
{
relation: 'self',
url: 'https://example.com/Patient?_count=50&_offset=60',
},
{
relation: 'first',
url: 'https://example.com/Patient?_count=50&_offset=0',
},
{
relation: 'previous',
url: 'https://example.com/Patient?_count=50&_offset=10',
},
{
relation: 'next',
url: 'https://example.com/Patient?_count=50&_offset=110',
}
];
To navigate between pages, simply follow the URLs provided in the Bundle.link
field.
The searchResourcePages()
method of the MedplumClient provides an async generator to simplify the iteration over resource pages.
for await (const patientPage of medplum.searchResourcePages('Patient', { _count: 10 })) {
for (const patient of patientPage) {
console.log(`Processing Patient resource with ID: ${patient.id}`);
}
}
The array returned by searchResourcePages
also includes a bundle
property that contains the original Bundle
resource. You can use this to access bundle metadata such as Bundle.total
and Bundle.link
.
Conclusion
In this guide, we've discussed how to perform paginated search queries using the _count
and _offset
search parameters, as well as the the Bundle.link
element.