Skip to main content

How to Filter Data Using Advanced Search Criteria

All the services in the iCure MedTech SDK offer the filterBy and the matchBy methods. They allow you to use complex search criteria to get entities and id of entities, respectively.
We can take as example the two method defined in the PatientApi:

function filterBy(filter: Filter<Patient>, nextPatientId?: string, limit?: number): Promise<PaginatedListPatient> { /*...*/ }
function matchBy(filter: Filter<Patient>): Promise<Array<string>> { /*...*/ }

you can learn more about these methods, their parameter and their return type in the reference. As for now, let us focus on the filterBy parameter.

The Filter DSL

Simple Queries

You can instantiate a filter for the Patient entity using the Filter builder class.

note

There is a filter class for each entity, the full list is available below

The Filter exposes some methods that let you define a query to filter your entity.
In the following example we will get all the Patients that a Healthcare Professional can access.

const patientsForHcpFilter = await new PatientFilter(api).forDataOwner(healthcarePartyId).build()
const patientsForHcp = await api.patientApi.filterBy(patientsForHcpFilter)
patientsForHcpFilter
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"$type": "PatientByHealthcarePartyFilter"
}
patientsForHcp
{
"rows": [
{
"id": "4ad3e283-9b9f-4338-a1a7-fdedf41ab1f4",
"rev": "1-55120a0278bc0ac126f82302f2ead524",
"identifiers": [],
"created": 1700058638682,
"modified": 1700058638682,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Astra",
"given": [
"Trillian"
],
"prefix": [],
"suffix": [],
"text": "Astra Trillian",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "female",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "9kAC6UWCEhfm64zfG2J3rfxeHb5vSzIl7XEew8lN7nE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Trillian",
"lastName": "Astra"
},
{
"id": "5871f2a2-11ff-4859-a697-64ab0801aba0",
"rev": "1-117919b506b146e69d941553efc739de",
"identifiers": [],
"created": 1700058638610,
"modified": 1700058638610,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Dent",
"given": [
"Arthur"
],
"prefix": [],
"suffix": [],
"text": "Dent Arthur",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "male",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "hxgaJAQk1egGCQejq8Sw3VmM0nd6AjyiVQTblYp+2Qw=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Arthur",
"lastName": "Dent"
},
{
"id": "bfa7e241-55e1-4fe2-b390-e1c9e473eb9f",
"rev": "1-c099a06169679ad3d6d0a764a5772124",
"identifiers": [],
"created": 1700058638704,
"modified": 1700058638704,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Beeblebrox",
"given": [
"Zaphod"
],
"prefix": [],
"suffix": [],
"text": "Beeblebrox Zaphod",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "indeterminate",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19420101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "C5MVOWLRrX3SR+Kqu5gFl6ofl4otM+YDKXHhFN/c8SE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Zaphod",
"lastName": "Beeblebrox"
}
]
}
info

Some filters require you to specify a Data Owner in order to filter the results. You can either use the forDataOwner() method, passing as parameter the id of the Data Owner you want filter the entities for, or the forSelf() method that will filter the entities for the current logged-in user.

caution

You must have access to an entity in order to retrieve it by any means, filtering included.

Specifying More Conditions

You can define more complex queries by adding more parameters. The results will be the set of entities which satisfy all the constraints at the same time.

const ageGenderFilter = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.dateOfBirthBetween(19511211, 19520203)
.byGenderEducationProfession('female')
.build()

const ageGenderPatients = await api.patientApi.filterBy(ageGenderFilter)
ageGenderFilter
{
"filters": [
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"minDateOfBirth": 19511211,
"maxDateOfBirth": 19520203,
"$type": "PatientByHealthcarePartyDateOfBirthBetweenFilter"
},
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"gender": "female",
"$type": "PatientByHealthcarePartyGenderEducationProfessionFilter"
}
],
"$type": "IntersectionFilter"
}
ageGenderPatients
{
"rows": [
{
"id": "4ad3e283-9b9f-4338-a1a7-fdedf41ab1f4",
"rev": "1-55120a0278bc0ac126f82302f2ead524",
"identifiers": [],
"created": 1700058638682,
"modified": 1700058638682,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Astra",
"given": [
"Trillian"
],
"prefix": [],
"suffix": [],
"text": "Astra Trillian",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "female",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "9kAC6UWCEhfm64zfG2J3rfxeHb5vSzIl7XEew8lN7nE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Trillian",
"lastName": "Astra"
}
]
}

In this case, the method will return all the patients that the practitioner with id healthcarePartyId can access, bborn between the 11th of December 1951 and the 3rd of February 1952, and whose gender is female.

Sorting Filters

When defining a filter with more than one condition, you can also set one of them as the sorting key of the final result:

const ageGenderSortedFilter = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.sort.dateOfBirthBetween(19391211, 19520203)
.byGenderEducationProfession('female')
.build()

const ageGenderSortedPatients = await api.patientApi.filterBy(ageGenderFilter)
ageGenderSortedFilter
{
"filters": [
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"minDateOfBirth": 19391211,
"maxDateOfBirth": 19520203,
"$type": "PatientByHealthcarePartyDateOfBirthBetweenFilter"
},
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"gender": "female",
"$type": "PatientByHealthcarePartyGenderEducationProfessionFilter"
}
],
"$type": "IntersectionFilter"
}
ageGenderSortedPatients
{
"rows": [
{
"id": "4ad3e283-9b9f-4338-a1a7-fdedf41ab1f4",
"rev": "1-55120a0278bc0ac126f82302f2ead524",
"identifiers": [],
"created": 1700058638682,
"modified": 1700058638682,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Astra",
"given": [
"Trillian"
],
"prefix": [],
"suffix": [],
"text": "Astra Trillian",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "female",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "9kAC6UWCEhfm64zfG2J3rfxeHb5vSzIl7XEew8lN7nE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Trillian",
"lastName": "Astra"
}
]
}

In this case, the method will return all the patients that the practitioner with id healthcarePartyId can access, born between the 11th of December 1939 and the 3rd of February 1952, and whose gender is female. The result will be sorted by date of birth in ascending order. If you don't specify the sorting key the data may still be ordered according to some field, but we do not guarantee that this will be a consistent behaviour.

info

In complex situations sorted filters may be less efficient than unsorted filters. You should not request sorting unless you really need sorted data.

Combining Filters

If you have more than one filter for the same entity, you can create a new filter that will return the intersection of their results using the intersection() static method of the FilterComposition class:

const filterByAge = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.dateOfBirthBetween(19511211, 19520203)
.build()

const filterByGender = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.byGenderEducationProfession('female')
.build()

const filterByGenderAndAge = FilterComposition.intersection(filterByAge, filterByGender)

const ageGenderExplicitPatients = await api.patientApi.filterBy(filterByGenderAndAge)
ageGenderExplicitPatients
{
"rows": [
{
"id": "4ad3e283-9b9f-4338-a1a7-fdedf41ab1f4",
"rev": "1-55120a0278bc0ac126f82302f2ead524",
"identifiers": [],
"created": 1700058638682,
"modified": 1700058638682,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Astra",
"given": [
"Trillian"
],
"prefix": [],
"suffix": [],
"text": "Astra Trillian",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "female",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "9kAC6UWCEhfm64zfG2J3rfxeHb5vSzIl7XEew8lN7nE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Trillian",
"lastName": "Astra"
}
]
}
note

This is equivalent to specify all the conditions in a single filter, as shown in the previous section.

Similarly, you can create a new filter that will return the union of more filters for the same entity using the union() static method of the FilterComposition class:

const filterFemales = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.byGenderEducationProfession('female')
.build()

const filterIndeterminate = await new PatientFilter(api)
.forDataOwner(user.healthcarePartyId)
.byGenderEducationProfession('indeterminate')
.build()

const filterFemaleOrIndeterminate = FilterComposition.union(filterFemales, filterIndeterminate)

const unionFilterPatients = await api.patientApi.filterBy(filterFemaleOrIndeterminate)
filterFemaleOrIndeterminate
{
"filters": [
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"gender": "female",
"$type": "PatientByHealthcarePartyGenderEducationProfessionFilter"
},
{
"healthcarePartyId": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"gender": "indeterminate",
"$type": "PatientByHealthcarePartyGenderEducationProfessionFilter"
}
],
"$type": "UnionFilter"
}
unionFilterPatients
{
"rows": [
{
"id": "4ad3e283-9b9f-4338-a1a7-fdedf41ab1f4",
"rev": "1-55120a0278bc0ac126f82302f2ead524",
"identifiers": [],
"created": 1700058638682,
"modified": 1700058638682,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Astra",
"given": [
"Trillian"
],
"prefix": [],
"suffix": [],
"text": "Astra Trillian",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "female",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19520101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "9kAC6UWCEhfm64zfG2J3rfxeHb5vSzIl7XEew8lN7nE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Trillian",
"lastName": "Astra"
},
{
"id": "bfa7e241-55e1-4fe2-b390-e1c9e473eb9f",
"rev": "1-c099a06169679ad3d6d0a764a5772124",
"identifiers": [],
"created": 1700058638704,
"modified": 1700058638704,
"author": "d78d44bc-ab8d-41fa-b763-2f0dfd1dce8f",
"responsible": "6b25372b-f1ac-4278-957a-cf3c19a210cc",
"tags": {},
"codes": {},
"names": [
{
"family": "Beeblebrox",
"given": [
"Zaphod"
],
"prefix": [],
"suffix": [],
"text": "Beeblebrox Zaphod",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "indeterminate",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"personalStatus": "unknown",
"dateOfBirth": 19420101,
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "C5MVOWLRrX3SR+Kqu5gFl6ofl4otM+YDKXHhFN/c8SE=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "Zaphod",
"lastName": "Beeblebrox"
}
]
}

In this case, the method will return all the patients that the practitioner with id hcpId can access and whose gender is indeterminate or whose gender is female.

caution

The sorting order of the results of a composition of filter created using one of those two methods is never guaranteed, even if one of the filter you used was sorted.

Base Query Methods

In the following list, you will find all the simple queries for each type of entity filter.

Coding

  • byIds(byIds: string[]): all the Codings corresponding to the ids passed as parameter.
  • byRegionLanguageTypeLabel(region?: string, language?: string, type?: string, label?: string): all the Codings that have the provided region, language, type, and label
info

If no condition is specified, the generated filter will return all the Coding in your database.

Observation

  • forDataOwner(dataOwnerId: string): all the Observations that the Data Owner passed as parameter can access.
  • forSelf(): all the Observations that the logged-in Data Owner.
  • byIds(byIds: string[]): all the Observations corresponding to the ids passed as parameter.
  • byIdentifiers(identifiers: Identifier[]): all the Observations that have the identifier passed as parameter.
  • byLabelCodeDateFilter(tagType?: string, tagCode?: string, codeType?: string, codeCode?: string, startValueDate?: number, endValueDate?: number, descending: boolean?): all the Observations that matches one of his labels or codes, or created in the provided date interval.
  • forPatients(crypto: IccCryptoXApi, patients: Patient[]): all the Observations related to a certain Patient.
  • byHealthElementIds(byHealthElementIds: string[]): all the Observations that have the Healthcare Element specified as parameter.

Healthcare Element

  • forDataOwner(dataOwnerId: string): all the Conditions that the Data Owner passed as parameter can access.
  • forSelf(): all the Observations that the logged-in Data Owner.
  • byIds(byIds: string[]): all the Conditions corresponding to the ids passed as parameter.
  • byIdentifiers(identifiers: Identifier[]): all the Conditions that have the identifier passed as parameter.
  • byLabelCodeFilter(tagType?: string, tagCode?: string, codeType?: string, codeCode?: string): all the Conditions that matches one of his labels or codes.
  • forPatients(crypto: IccCryptoXApi, patients: Patient[]): all the Conditions related to a certain Patient.

Healthcare Professional

  • byIds(byIds: string[]): all the Healthcare Professionals corresponding to the ids passed as parameter.
  • byLabelCodeFilter(labelType?: string, labelCode?: string, codeType?: string, codeCode?: string): all the Healthcare Professionals whose label or code matches the one passed as parameter.
info

If no condition is specified, the generated filter will return all the Healthcare Professionals in your database.

Medical Device

  • byIds(byIds: string[]): all the Medical Devices corresponding to the ids passed as parameter.
info

If no condition is specified, the generated filter will return all the Medical Devices in your database.

Notification

  • forDataOwner(dataOwnerId: string): all the Notifications that the Data Owner passed as parameter can access. Note: this field must be specified in all the queries.
  • forSelf(): all the Observations that the logged-in Data Owner.
  • byIds(byIds: string[]): all the Notifications corresponding to the ids passed as parameter.
  • withType(type: NotificationTypeEnum): all the Notifications that are of the type passed as parameter.
  • afterDate(fromDate: number): all the Notifications created after the timestamp passed as parameter.

Patient

  • forDataOwner(dataOwnerId: string): all the Patients that the Data Owner passed as parameter can access.
  • forSelf(): all the Observations that the logged-in Data Owner.
  • byIds(byIds: string[]): all the Patients corresponding to the ids passed as parameter.
  • byIdentifiers(identifiers: Identifier[]): all the Patients that have the identifier passed as parameter.
  • byGenderEducationProfession(gender: PatientGenderEnum, education?: string, profession?: string): all the Patients that matches the gender, the education, or the profession passed as parameters.
  • withSsins(withSsins: string[]): all the Patients corresponding to the SSIN numbers passed as parameters.
  • ofAge(age: number): all the Patients of the age passed as parameter.
  • dateOfBirthBetween(from: number, to: number) all the Patients whose birthdate is between the ones passed as parameters.
  • containsFuzzy(searchString: string): all the patients which first name, last name, maiden name or spouse name matches, even partially, the string passed as parameter.

User

  • byIds(byIds: string[]): all the Users corresponding to the ids passed as parameter.
  • byPatientId(patientId: string): the User that has the patient id passed as parameter.
info

If no condition is specified, the generated filter will return all the Users in your database.