This is a follow up to my previous post that covered the topic of FHIR Data Model with Couchbase N1QL. In this blog, I will discuss the topic of how to implement the FHIR Search REST API Server over the Couchbase services, including actual examples of how the different FHIR search patterns work with Couchbase using the synthetic FHIR data provided by Synthea.
Please refer to my previous blog for background information on FHIR Data Model with Couchbase N1QL.
Why is this of interest to you
- Your organization is planning to develop an FHIR compliant Electronic Health Record system (EHR), and you are looking into taking advantage of the many benefits of NoSQL databases, such as Distributed, High Availability, XDCR, and Multi-Dimensional Scalability.
- You are an architect, or developer and like understand how Couchbase JSON database can greatly reduce the complexity of your applications, by relegating the complex FHIR Search [https://www.hl7.org/fhir/searchparameter-registry.html] processing to the database server layer.
- You are a data analyst and like to understand how you can leverage your SQL knowledge to query FHIR data directly with Couchbase N1QL and Full-Text-Search.
- You are interested in finding out how Couchbase N1QL, a SQL for JSON, can provide an efficient way to query a JSON data modelt hat is both hierarchical and relational in nature, as defined by HL7 Administrative Module.
FHIR Application with Couchbase
The diagram above shows the processes involved in a typical FHIR application. The FHIR Rest server is central to this application, and needs to support the search specifications as specified by FHIR https://www.hl7.org/fhir/search.html. The REST server manages all the interactions between the client applications and translates the FHIR search requests into N1QL statements, and submits the requests to the Couchbase Query Service.
How to set up the FHIR Server with Couchbase
You can set up the Couchbase FHIR API server, and the Couchbase NoSQL database on a single server, or even your laptop. The setup process requires:
- Installing Couchbase Server 6.5.
- Load the Synthea Data into the Couchbase Server.
- Deploy the dotnet FHIR Server code.
Please follow the instructions https://github.com/AV25242/dotnet-fhir-server-couchbase.git
FHIR Sample Data Set
Before you start using FHIR search to query, let’s familiarize ourselves with the FHIR sample data set.
- The Synthea data set consists of 1K synthetic patient records.
- The patient record is in a FHIR resource bundle format, meaning a patient record includes all of the patient’s related FHIR objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
"Practitioner" "ImagingStudy" "MedicationRequest" "Condition" "Device" "DiagnosticReport" "CarePlan" "Encounter" "CareTeam" "Claim" "Procedure" "Immunization" "Observation" "MedicationAdministration" "Organization" "Goal" "ExplanationOfBenefit" "AllergyIntolerance" |
For the purpose of this demonstration, the patient resource bundle have been normalized into individual resource type documents, to allow us to query the FHIR object directly or indirectly via the reference id of the object.
FHIR searches
You can test out the REST API server using any REST clients of your choice. For simplicity, I use CURL on my terminal.
1. Search any FHIR resource
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient |
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Practitioner |
2. Search resource by id
All FHIR resources have an id identifier, and can be searched directly.
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient/8850c4aa-cb77-4659-8373-980882405846 |
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient?id=8850c4aa-cb77-4659-8373-980882405846 |
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Organization?id=d32bd7bd-4211-34d8-a08b-b1b2b810d41b |
3. Search resource by any top level field
Search all insurance Claims that were provided by “BAYSIDE MEDICAL CENTER”
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Claim?provider.display=BAYSTATE MEDICAL CENTER |
4. Search resource by name – N1QL ARRAY Search
The FHIR resource has a comprehensive structure to capture the resource name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
"name": [ { "family": "Wizard", "given": [ "Buffy" ], "prefix": [1 item], "use": "official" }, { "family": "Schneider", "given": [ "Tootsie" ], "prefix": [1 item], "use": "maiden" } ] |
The FHIR search on name has to take into account all the different names the patient may use.
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient/?name=Buffy |
5. Search Patients by Medical Identifier – N1QL ARRAY Search
FHIR also supports identifiers for the resource. In the example below, a patient can be identified with his/her SSN and OID (for non-FHIR systems).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
"patient": { "address": [1 item], "birthDate": "1946-11-29", "communication": [1 item], "deceasedDateTime": "1983-03-25T09:56:18-08:00", "extension": [7 items], "gender": "female", "id": "b495844d-22d0-4045-a00d-99f6799df265", "identifier": [ {2 items}, {3 items}, { "system": "http://hl7.org/fhir/sid/us-ssn", "type": {2 items}, "value": "999-46-2135" }, { "system": "urn:oid:2.16.840.1.113883.4.3.25", "type": {2 items}, "value": "S99963447" }, {3 items} ], "maritalStatus": {2 items}, "multipleBirthBoolean": false, "name": [1 item], "resourceType": "Patient", "telecom": [1 item], "text": {2 items} } |
Search Patient by the SSN identifier
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient?identifier=http://hl7.org/fhir/sid/us-ssn|999-46-2135 |
6. Search resource by medical system/code – N1QL ARRAY Search
FHIR uses the medical code to identify Procedure, Observation, or DiagnosticReport.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
"diagnosticreport": { "category": [1 item], "code": { "coding": [ { "code": "57698-3", "display": "Lipid Panel", "system": "http://loinc.org" } ], "text": "Lipid Panel" }, "effectiveDateTime": "2016-08-17T14:24:27-07:00", "encounter": {1 item}, "id": "38f2e919-894c-4277-ba00-372c18c9cced", "issued": "2016-08-17T14:24:27.878-07:00", "resourceType": "DiagnosticReport", "result": [4 items], "status": "final", "subject": {1 item} } |
Search DiagnosticReport by its system & code
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/DiagnisticReport?code=http://loinc.org|57698-3 |
7. Search resource by Phone / Email – N1QL ARRAY Search
FHIR record encapsulates all the communication channels to the resource in the “telecom” field.
1 2 3 4 5 6 7 8 9 10 11 12 |
"telecom": [ { "system": "email", "use": "work", "value": "Quinton758.Hammes673@example.com" }, { "system": "phone", "use": "home", "value": "555-270-6484" } ] |
The FHIR search on telecom has to take into account all the different telecom types the resource may use.
Search Patients by phone
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient/?phone=555-270-6484 |
Search Practitioners by email
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Practioner/?email=Quinton758.Hammes673@example.com |
Search Hospitals by phone
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Organization/?phone=978-524-7933 |
8. Search resource using Date Range – N1QL Range Scan
FHIR objects may include a datetime range to indicate the period in which an event occurred.
1 2 3 4 |
"performedPeriod": { "end": "2011-07-06T23:03:22-07:00", "start": "2011-07-06T22:48:22-07:00" }, |
Search Procedures that took place between two dates
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Procedure?performedPeriod.start=ge2011-07-07&performedPeriod.end=le2011-07-08 |
9. Search resource with _text search – Couchbase FTS
FHIR search specification also includes a text search capability. A search request using the ‘_text’ field will instruct the server to perform a text search on all the text field.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
"condition": { "abatementDateTime": "2019-06-01T20:53:48-07:00", "clinicalStatus": {1 item}, "code": { "coding": [1 item], "text": "Fracture of ankle" }, "encounter": {1 item}, "id": "f2e4b232-513c-4222-9568-6fbe096bb6ba", "onsetDateTime": "2019-04-02T20:53:48-07:00", "recordedDate": "2019-04-02T20:53:48-07:00", "resourceType": "Condition", "subject": {1 item}, "verificationStatus": {1 item} } |
Search Conditions with the term ‘Fracture’ in text description.
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Condition?_text=Fracture |
Search Observations with the term ‘Cholesterol’’ in text description.
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Observation?_text=Cholesterol |
10. Search Patients by their related objects – N1QL JOIN
The FHIR data model is relational in nature. The objects that are associated with a Patient contain the Patient’s id in the subject field. A patient has multiple CarePlans, and the plan has a subject field with the patient’s id to denote that the care plan belongs to the patient.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
"careplan": { "activity": [2 items], "addresses": [1 item], "careTeam": [1 item], "category": [1 item], "encounter": {1 item}, "id": "49b2239e-da9c-447a-9e7c-f5721339cf2f", "intent": "order", "period": { "start": "2015-03-22T21:38:17-07:00" }, "resourceType": "CarePlan", "status": "active", "subject": { "reference": "urn:uuid:9aa55fa8-0422-4ca4-bc22-099aea53a590" }, "text": {2 items} } |
Using the subject.reference field, the FHIR REST server can implement a database JOIN between the Patient and the related objects, to allow a search for the patient record who owns a specific plan with a plan id value
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient?CarePlan.id=49b2239e-da9c-447a-9e7c-f5721339cf2f |
Search all Patients who had a particular Observation code
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient?Observation.code=http://loinc.org|29463-7 |
Search all Patients who have had a s particular medical Condition
1 |
>curl -X GET http://<fhir-server-ip>/Fhir/api/Patient?Condition.code.text=Hypertension |
Why Couchbase is a better platform to build your FHIR Server
A quick Google on FHIR Server returns 300K results, and the HL7 FHIR implementation page lists over dozen open source projects. Ready built FHIR server implementations are also available from many vendors. These implementations rely on different database technologies from traditional RDBMS, as well as many of the current NoSQL databases in the market today.
The dotnot-fhir-server-couchbase provides several examples on how you can build the FHIR search specifications using the Couchbase platform. The code translates the FHIR API search APIs and parameters into Couchbase N1QL statements, then submits them to the Couchbase Query service, where all the processing are processed. This approach can reduce the complexity in the REST server or the REST client application. A few key points to note:
- The FHIR JSON data are stored as-is in the Couchbase Data Service. There are no pre/post processing required when you need to POST/GET the FHIR document to/from the server.
- Couchbase N1QL query language has a rich set of operations that support the processing of the hierarchical data of the FHIR JSON format. Allowing seamless access to nested array of data, such as those used to describe patient’s conditions, observations, treatments, and diagnostic reports.
- FHIR requirements for Text Search can be met directly in Couchbase Full Text Search with N1QL Search() function, there is no need to map your searches to Lucene, ElasticSearch or Solr.
- FHIR chained search specifications could require a FHIR server implementation to submit multiple searches to the database in order process the request. However with N1QL, an ANSI join query can result in a much simpler code to meet the requirement.
Summary
FHIR Rest Servers are being implemented in all types of platforms. The search protocols are relatively simple, focusing on the support of retrieving Patient, and other FHIR related objects by their specific attributes. The search APIs insulate the REST client from complex hierarchical and array processing, which are fundamentals to JSON data format. However, the specification, as it is currently stands:
- Does not define a clear way to allow querying of patients (or other FHIR objects) by its related information, other than a simple parent and child capability.
- There is no support for aggregation, thus limiting any analysis capabilities.
Because of these limitations, the REST client applications can become more complex as it needs to embed the logic of traversing the FHIR data model. The example REST Server API code in this blog article, seeks to illustrate three key points
- The simplicity of implementing searching on array elements using Couchbase N1QL array construct.
- The ability to push down to the Couchbase Query service, to perform the search on Patient objects using related objects. In effect, leveraging N1QL ANSI JOIN supports.
- The ability to seamlessly integrate Full Text Search capabilities with Couchbase N1QL, without the need to use dedicated FTS platforms such ElasticSearch or Solr, as suggested in the FHIR Search specification.
I would also like to thank Arun Vijayraghavan, our Principal Product Manager for all Couchbase SDKs, who developed the dotnet-fhir-server-couchbase code, and the feedback from customers who have helped reviewing our FHIR search implementation. Please let us know if you have any questions, feedback or running into any issue setting the environment.
Resources
- Fast Healthcare Interoperability Resource: https://www.hl7.org/fhir/index.html
- SyntheticMass: “Jason Walonoski, Mark Kramer, Joseph Nichols, Andre Quina, Chris Moesel, Dylan Hall, Carlton Duffett, Kudakwashe Dube, Thomas Gallagher, Scott McLachlan, Synthea: An approach, method, and software mechanism for generating synthetic patients and the synthetic electronic health care record, Journal of the American Medical Informatics Association, Volume 25, Issue 3, March 2018, Pages 230–238, https://doi.org/10.1093/jamia/ocx079“
- N1QL Tutorial: https://query-tutorial.couchbase.com/tutorial/#1
- FHIR Search Parameters: https://www.hl7.org/fhir/searchparameter-registry.html
hello, thanks for this but i was unable to download the synthea sample data from https://storage.googleapis.com/synthea-public/synthea_sample_data_fhir_r4_sep2019.zip
while following this : https://github.com/AV25242/dotnet-fhir-server-couchbase.git.
Any ideas how i can the sample data ?
Hi loalu – The file may have been moved. But you can still find it from the SyntheticMass site. https://synthetichealth.github.io/synthea-sample-data/downloads/synthea_sample_data_fhir_r4_sep2019.zip
-binh