3.9.1FHIRPath Expressions

 

Paths are defined using FHIRPath, which is an expression language defined by FHIR. In its simplest form, this can take the form of a single dotted path:

Patient.name.given

In the example above, the FHIRPath expression matches all of the patient's given names. If this path is used as the expression in a Custom Search Parameter, any values for the patient's given name(s) will be indexed by the search parameter.

Paths can also perform more advanced lookups. This page outlines expressions to satisfy various common needs, and includes example SearchParameters that use them.

3.9.2Testing FHIRPath Expressions

 

When developing a FHIRPath expresion, the _fhirpath parameter can be helpful. This parameter can be added to any FHIR REST URL where the response will be a resource or a Bundle resource containing a collection of resources (e.g. a FHIR Read or a FHIR Search). When it is present in the request URL, the parameter value will be parsed as a FHIRPath expression and then applied against the response resource.

For example, suppose you have a FHIR repository containing the following resource:

{
   "resourceType": "Patient",
   "id": "123",
   "extension": [{
     "url": "http://acme.com/eye-color",
      "valueCode":"hazel"
   }]
}

the following URL will fetch a resource with ID Patient/123 and then apply a FHIRPath expression against it. You can use this to test whether your expression returns the desired value from the resource in question. http://localhost:8000/Patient/123?_fhirpath=Patient.extension('http://acme.com/eye-color').value.as(code)

This will produce a result like the following if the expression is correct:

{
  "resourceType": "Parameters",
  "parameter": [ {
    "name": "result",
    "part": [ {
      "name": "expression",
      "valueString": "Patient.extension('http://acme.com/eye-color').value.as(code)"
    }, {
      "name": "result",
      "valueCode": "hazel"
    } ]
  } ]
}

3.9.2.1Viewing Complete Indexes

Another mechanism to test search parameter expressions is to create your search parameter as well as a resource that you want to index, and then perform a Reindex Dry-Run against your candidate. This shows all existing indexes and any that will be newly created by your search parameter.

3.9.3Expression: Extension With Reference Value

 

This example indexes the value on a custom extension that is added to a resource. Note that the extension does not need to be declared anywhere (aside from in the SearchParameter resource) in order for this example to work.

Expression:

Patient.extension('http://acme.com/doctor').value.as(Reference)

Example resource that would be indexed by this expression:

{
  "resourceType": "Patient",
  "extension": [{
    "url": "http://acme.com/doctor",
    "valueReference": {
      "reference": "Practitioner/A"
    }
  }]
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "status": "active",
  "name": "doctor", 
  "url": "http://acme.com/doctor-search-parameter", 
  "code": "doctor",
  "base": [ "Patient" ],
  "type": "reference",
  "expression": "Patient.extension('http://acme.com/doctor').value.as(Reference)"
}

Example search URL using this parameter: http://localhost:8000/Patient?doctor=Practitioner/A

3.9.4Expression: Nested Extension

 

This example indexes the value on an extension nested inside another extension.

Expression:

Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')

Note that it is not necessary to specify the .value at the end of the FHIRPath expression if the actual value will be a primitive value with a type that is appropriate for the type of the search parameter. For example, if the http://acme.org/bar extension has a value of type string and the SearchParameter is of type string, or if the extension has a value of type Identifier and the value is of type token.

If the value is of type Coding and you wish to specifically index the display value as a string, you could use the following path:

Patient.extension('http://acme.org/foo').extension('http://acme.org/bar').value.as(Coding).display

Example resource that would be indexed by this expression:

{
  "resourceType": "Patient",
  "extension": [ {
    "url": "http://acme.org/foo",
    "extension": [ {
      "url": "http://acme.org/bar",
      "valueString": "HELLO"
    } ]
  } ],
  "name": [ {
    "family": "P2"
  } ]
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "title": "Foo",
  "status": "active",
  "code": "foo",
  "base": [ "Patient" ],
  "type": "string",
  "expression": "Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')",
  "xpathUsage": "normal"
}

Example search URL using this parameter: http://localhost:8000/Patient?foo=hello

3.9.5Expression: Contained Resource

 

The following example indexes on a field that is found within a contained resource inside the resource that is being indexed.

Expression:

Observation.specimen.resolve().receivedTime

Example resource that would be indexed by this expression:

{
  "resourceType": "Observation",
  "id": "O1",
  "contained": [
    {
      "resourceType": "Specimen",
      "id": "FOO",
      "receivedTime": "2011-01-01"
    }
  ],
  "status": "final",
  "specimen": {
    "reference": "#FOO"
  }
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "status": "active",
  "name": "specimen-received", 
  "url": "http://acme.com/specimen-received-search-parameter", 
  "code": "specimen-received",
  "base": [ "Observation" ],
  "type": "date",
  "expression": "Observation.specimen.resolve().receivedTime"
}

Example search URL using this parameter: http://localhost:8000/Observation?specimen-received=2011-01-01

3.9.6Expression: Bundle (FHIR Message) Entry Resource

 

When storing Bundles directly (i.e. by POST-ing them to the /Bundle endpoint as opposed to processing them as FHIR transactions), this path can be used to index on a value within an individual resource found within the Bundle.

Expression:

Bundle.entry.resource.as(MessageHeader).id

Example resource that would be indexed by this expression:

{
  "resourceType": "Bundle",
  "type": "message",
  "entry": [
    {
      "resource": {
        "resourceType": "MessageHeader",
        "id": "123"
      }
    }
  ]
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "status": "active",
  "name": "message-header-id", 
  "url": "http://acme.com/message-header-id-search-parameter", 
  "code": "message-header-id",
  "base": [ "Bundle" ],
  "type": "token",
  "expression": "Bundle.entry.resource.as(MessageHeader).id"
}

Example search URL using this parameter: http://localhost:8000/Bundle?message-header-id=123

3.9.7Expression: Bundle (FHIR Document) Entry Resource

 

This example shows a FHIR Document (a bundle with a Bundle.type of document where the first entry contains a Composition resource) with a custom search parameter indexing a field within the Composition. This example allows clients to search for documents with a given encounter reference.

Expression:

Bundle.entry[0].resource.as(Composition).encounter

Example resource that would be indexed by this expression:

{
  "resourceType": "Bundle",
  "type": "document",
  "entry": [
    {
      "resource": {
        "resourceType": "Composition",
        "encounter": {
          "reference": "Encounter/2"
        }
      }
    }
  ]
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "status": "active",
  "name": "document-encounter", 
  "url": "http://acme.com/document-encounter-search-parameter", 
  "code": "document-encounter",
  "base": [ "Bundle" ],
  "type": "reference",
  "expression": "Bundle.entry[0].resource.as(Composition).encounter"
}

Example search URL using this parameter: http://localhost:8000/Bundle?document-encounter=Encounter/2

3.9.8Example: Indexing Automatically Created Placeholder Resources

 

If you are using Auto-Create Placeholder Reference Targets, you may wish to have a way of easily finding these placeholder resources.

The following expression searches for presence of the placeholder extension in resources. Note the where(value = true) portion at the end. This filters out any negative values, meaning that only placeholder resources will be indexed, and non-placeholder resources will not generate any indexing. This saves space, but means that you can not perform a negative search (ie. find any non-placeholder resources). If you need to also be able to search for non-placeholder resources, you can remove this part of the expression.

extension('http://hapifhir.io/fhir/StructureDefinition/resource-placeholder').where(value = true)

Example resource that would be indexed by this expression:

{
  "resourceType": "Patient",
  "id": "ABC",
  "meta": {
    "versionId": "1",
    "lastUpdated": "2025-01-01T19:07:19.616-05:00"
  },
  "extension": [ {
    "url": "http://hapifhir.io/fhir/StructureDefinition/resource-placeholder",
    "valueBoolean": true
  } ]
}

Example SearchParameter resource using this expression (add additional types to the Base element if you have other resource types being created as placeholders):

{
  "resourceType": "SearchParameter",
  "name": "placeholder",
  "status": "active",
  "description": "Index resources which were automatically created as placeholders",
  "code": "placeholder",
  "base": [ "Patient" ],
  "type": "token",
  "expression": "extension('http://hapifhir.io/fhir/StructureDefinition/resource-placeholder').where(value = true)",
  "xpathUsage": "normal"
}

Example search URL using this parameter: http://localhost:8000/Patient?placeholder=true

3.9.9Expression: Multiple Paths

 

This example indexes multiple paths, meaning it can be used to provide one search parameter that will look for a value in multiple places within a resource.

Expression:

DiagnosticReport.performer | DiagnosticReport.resultsInterpreter

Example resource that would be indexed by this expression:

{
  "resourceType": "DiagnosticReport",
  "resultsInterpreter": {
    "reference": "Practitioner/A"
  }
}

Example SearchParameter resource using this expression:

{
  "resourceType": "SearchParameter",
  "status": "active",
  "name": "performer-or-interpreter", 
  "url": "http://acme.com/performer-or-interpreter-search-parameter", 
  "code": "performer-or-interpreter",
  "base": [ "DiagnosticReport" ],
  "type": "reference",
  "expression": "DiagnosticReport.performer | DiagnosticReport.resultsInterpreter"
}

Example search URL using this parameter: http://localhost:8000/DiagnosticReport?performer-or-interpreter=Practitioner/A