Basic Search
Intro
One of the most basic operations when working with the Medplum FHIR API is to query resources that fulfill certain criteria.
The FHIR specification defines rich search semantics to support these use cases, and this guide will cover some of the basic search operations to get you started. If you're new to FHIR, we'd recommend checking out our FHIR Basics page first.
Search Parameters
To maintain performance, FHIR doesn't allow Resources to be queried by arbitrary elements. Instead, it defines a set of search parameters for each Resource Type.
Let's look at a few examples with the Patient
resource. The Patient
reference docs have a table that list out all the available search parameters.
Search Parameter | Type | Description | Expression |
---|---|---|---|
birthdate | date | The patient's date of birth | Patient.birthDate |
Some search parameters, such as birthdate
, map directly to a top-level element, Patient.birthDate
. (Note that the search parameter is all lowercase, even though the element is camel case)
Search Parameter | Type | Description | Expression |
---|---|---|---|
address-city | string | A city specified in an address | Patient.address.city |
Some search parameters map to nested elements, such as address-city
, which maps to Patient.address.city
. Since Patient.address
is an array element, this search parameter will search all addresses saved to the Patient
.
Search Parameter | Type | Description | Expression |
---|---|---|---|
death-date | date | The date of death has been provided and satisfies this search value | Patient.deceased |
Lastly, some search parameters rename/alias the target element. For example, the death-date
maps to the Patient.deceased
element.
Basic Search
To search for resources, you can simply add search parameters and values as query parameters in your GET
request.
The Medplum Client SDK also provides the search
helper method, which accepts a string
or object
.
- TypeScript
- cURL
await medplum.search('Patient', { birthdate: '1940-03-29' });
// OR
await medplum.search('Patient', 'birthdate=1940-03-29');
curl https://api.medplum.com/fhir/R4/Patient?birthdate=1940-03-29
This request will return a FHIR Bundle
resource, which contains the query results as well as some metadata. The Bundle.entry
element will contain an array with each Bundle.entry[i].resource
being a search result.
// returns
{
resourceType: 'Bundle',
type: 'searchset',
entry: [
{
fullUrl: 'http://api.medplum.com/Patient/1',
resource: {
resourceType: 'Patient',
id: '1',
name: [
{
given: ['John'],
family: 'Doe',
},
],
birthDate: '1940-03-29',
},
},
{
fullUrl: 'http://api.medplum.com/Patient/2',
resource: {
resourceType: 'Patient',
id: '2',
name: [
{
given: ['Homer'],
family: 'Simpson',
},
],
birthDate: '1940-03-29',
},
},
],
link: [
{
relation: 'self',
url: 'http://api.medplum.com/Patient?birthdate=1940-03-29',
},
],
}
Because iterating over the Bundle.entry
array is such a common pattern, the Medplum SDK provides the searchResources
convenience method that unwraps the bundle and returns an array of resources.
await medplum.searchResources('Patient', { name: 'Simpson', birthdate: '1940-03-29' });
// OR
await medplum.searchResources('Patient', 'name=Simpson&birthdate=1940-03-29');
// returns
// [
// {
// resourceType: 'Patient',
// id: '2',
// name: [
// {
// given: ['Homer'],
// family: 'Simpson',
// },
// ],
// birthDate: '1940-03-29',
// },
// ]
The array returned by searchResources
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
.
Searching Multiple Criteria
You can perform and AND search by specifying multiple query parameters
- TypeScript
- cURL
await medplum.searchResources('Patient', { name: 'Simpson', birthdate: '1940-03-29' });
// OR
await medplum.searchResources('Patient', 'name=Simpson&birthdate=1940-03-29');
// returns
// [
// {
// resourceType: 'Patient',
// id: '2',
// name: [
// {
// given: ['Homer'],
// family: 'Simpson',
// },
// ],
// birthDate: '1940-03-29',
// },
// ]
curl https://api.medplum.com/fhir/R4/Patient?name=Simpson&birthdate=1940-03-29
Specifying comma separated values performs an OR operation for that search parameter
- TypeScript
- cURL
await medplum.searchResources('Task', { status: 'completed,cancelled' });
// OR
await medplum.searchResources('Task', 'status=completed,cancelled');
curl https://api.medplum.com/fhir/R4/Task?status=completed,cancelled
Searching by Reference
You can use reference
search parameters to search for resources based on the resources they refer to.
The syntax for this kind of search is [parameter]=[resourceType]/[id]
. You can use the getReferenceString()
utility method to help with construct your query.
For example, to search for all Observation
resources that reference a Patient
with the ID "1234"
:
- TypeScript
- cURL
/*
curl https://api.medplum.com/fhir/R4/Observation?subject=Patient/1234
*/
const patient: Patient = { resourceType: 'Patient', id: '1234' };
await medplum.searchResources('Observation', { subject: getReferenceString(patient) });
// OR
await medplum.searchResources('Observation', { subject: 'Patient/1234' });
curl https://api.medplum.com/fhir/R4/Observation?subject=Patient/1234
Strings vs. Tokens
FHIR defines two different types of "string" search parameters: string
and token
. Their search behaviors are quite different, and it's important to understand the difference.
string | token |
---|---|
Case insensitive Match strings that start with query No | Case sensitive Exact string match Optional |
string
A string
search parameter is used when searching for a specific word or phrase within a resource. This type of search is more general and allows for partial matches, such as searching for patients whose names contain the word "Smith". Searches are case insensitive, and any result that starts with the query string will be returned.
For example, the following search will return patients with the names "eve"
, "Eve"
, "Evelyn
", but not "Steve"
medplum.search('Patient', 'name=eve')
You can use the :contains
modifier to search anywhere inside the target string, and the :exact
modifier to perform a case-sensitive, exact string match (see below)
token
A token
search parameter is used when searching for exact matches of a specific code or identifier, such as a medical terminology code (CodeableConcept
) or a unique patient identifier ( Identifier
). By default, searching a token
performs a case-sensitive, exact string match.
Additionally, many token
elements are namespaced by a system
string. This is because FHIR resources often contain codes or identifiers that come from different code systems, such as LOINC or SNOMED CT, which may use the same code or identifier for different concepts.
You can restrict your token
search to a specific system by using the syntax <parameter>=<system>|<value>
The following search would find all patients with any identifier that equals "12345"
medplum.searchResources('Patient', 'identifier=12345');
If we only wanted to search for patients whose social security number was "12345"
, we could use the system string "http://hl7.org/fhir/sid/us-ssn"
as follows:
medplum.searchResources('Patient', 'identifier=http://hl7.org/fhir/sid/us-ssn|12345');
We can also check for the presence of a particular identifier by dropping the <value>
and using the syntax <parameter>=<system>|
.
To find all Patients
that have a social security number:
medplum.searchResources('Patient', 'identifier=http://hl7.org/fhir/sid/us-ssn|');
Search Modifiers
The FHIR spec includes a set of modifiers to change the way a specific search parameters behave. They are used by appending the string :<modifier-name>
to the search parameter. While the FHIR search specification details all the available modifiers, we'll describe some of the most common modifiers here.
:not
:not
excludes the specified values from results.
For example, search for all Tasks
where status is not completed
:
- TypeScript
- cURL
await medplum.searchResources('Task', { 'status:not': 'completed' });
//OR
await medplum.searchResources('Task', 'status:not=completed');
curl https://api.medplum.com/fhir/R4/Patient?status:not=completed
:missing
:missing
specifies whether or not to include values where the specified search parameter is present/absent
For example, searching for all Patients
with missing birthDates
.
- TypeScript
- cURL
await medplum.searchResources('Patient', { 'birthdate:missing': 'true' });
// OR
await medplum.searchResources('Patient', 'birthdate:missing=true');
curl https://api.medplum.com/fhir/R4/Patient?birthdate:missing=true
:contains
:contains
allows you to perform a partial match on string
search parameters.
For example, searching for Patients
whose name includes the substring "stein"
- TypeScript
- cURL
await medplum.searchResources('Patient', { 'name:contains': 'eve' });
// OR
await medplum.searchResources('Patient', 'name:contains=eve');
// Return patients with the names `"eve"`, `"Eve"`, `"Evelyn`", AND `"Steve"`
curl https://api.medplum.com/fhir/R4/Patient?name:contains=eve
Searching by Comparison
FHIR provides a mechanism to search for resources that have a value greater or less than a certain threshold, or that have a value within a specific range, by adding a prefix to your query value. The table below lists the common prefixes used for quantity
, number
, and date
search parameters:
Prefix | Description |
---|---|
eq | equal |
ne | not equal |
gt | greater than |
lt | less than |
ge | greater than or equal to |
le | less than or equal to |
sa | starts after |
eb | ends before |
This example shows how to find all RiskAssessments
with a probability
greater than 0.8.
- TypeScript
- cURL
await medplum.searchResources('RiskAssessment', { probability: 'gt0.8' });
// OR
await medplum.searchResources('RiskAssessment', 'probability=gt0.8');
curl https://api.medplum.com/fhir/R4/RiskAssessment?probability=gt0.8
You can search an inclusive range using an AND search
- TypeScript
- cURL
await medplum.searchResources('Observation', [
['value-quantity', 'gt40'],
['value-quantity', 'lt60'],
]);
// OR
await medplum.searchResources('Observation', 'value-quantity=gt40&value-quantity=lt60');
curl https://api.medplum.com/fhir/R4/Observation?value-quantity=gt40&value-quantity=lt60
Because we are specifying the value-quantity
parameter twice in this query, we must pass a string[][]
as the second argument to searchResources()
You can search an exclusive range using an OR search
- TypeScript
- cURL
await medplum.searchResources('Observation', { 'value-quantity': 'lt40,gt60' });
// OR
await medplum.searchResources('Observation', 'value-quantity=lt40,gt60');
https://api.medplum.com/fhir/R4/Observation?value-quantity=lt40,gt60
Sorting the Results
You can sort your search results by using the special search parameter _sort
.
The _sort
parameter allows you specify a list of search parameters to sort by, in order.
The example below searches for all RiskAssessments
, sorted by their probability
, then by date
.
- TypeScript
- cURL
await medplum.searchResources('RiskAssessment', { _sort: 'probability,date' });
// OR
await medplum.searchResources('RiskAssessment', '_sort=probability,date');
https://api.medplum.com/fhir/R4/RiskAssessment?_sort=probability,date
Reversing the sort order
To sort in descending order, prepend the search parameter with a minus sign -
. The following example returns RiskAssessments
, in descending order of probability
:
- TypeScript
- cURL
await medplum.searchResources('RiskAssessment', { _sort: '-probability' });
// OR
await medplum.searchResources('RiskAssessment', '_sort=-probability');
https://api.medplum.com/fhir/R4/RiskAssessment?_sort=-probability
Sorting by updated time
FHIR also provides the special search parameter, _lastUpdated
, to search by the last updated time for a resource. The following example searches for the most recently updated RiskAssessments
resources:
- TypeScript
- cURL
await medplum.searchResources('RiskAssessment', { _sort: '-_lastUpdated' });
// OR
await medplum.searchResources('RiskAssessment', '_sort=-_lastUpdated');
https://api.medplum.com/fhir/R4/RiskAssessment?_sort=-_lastUpdated
Getting the total number of results
You can use the special search parameter, _total
, to include the total number of matching resources in your search results. This information is particularly useful for pagination and understanding the scope of the data you are dealing with.
See the paginated search guide for more info.
Conclusion
This article covers the basic FHIR search functionality needed to build a healthcare application. The next guides will cover more advanced topics such as paginated search and using GraphQL for retrieving linked Resources.