Filtrado de Datos
FHIRPath proporciona un rico conjunto de funciones para reducir colecciones a los elementos que necesita. Esta página cubre las funciones de filtrado e inspección más importantes con ejemplos completos.
where() – Filtrar por Criterio
La función where() evalúa una expresión booleana contra cada elemento en la colección de entrada y devuelve solo los elementos donde la expresión es true.
Filtrado de Telecom por Sistema
package main
import (
"fmt"
"log"
"github.com/gofhir/fhirpath"
)
func main() {
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-filter-1",
"telecom": [
{"system": "phone", "value": "+1-555-0100", "use": "home"},
{"system": "phone", "value": "+1-555-0101", "use": "work"},
{"system": "email", "value": "jane.doe@example.com", "use": "home"},
{"system": "fax", "value": "+1-555-0199", "use": "work"}
]
}`)
// Get only phone numbers
phones, err := fhirpath.EvaluateToStrings(patient,
"Patient.telecom.where(system = 'phone').value")
if err != nil {
log.Fatal(err)
}
fmt.Println("Phones:", phones)
// Output: Phones: [+1-555-0100 +1-555-0101]
// Get the home email address
homeEmail, err := fhirpath.EvaluateToString(patient,
"Patient.telecom.where(system = 'email' and use = 'home').value")
if err != nil {
log.Fatal(err)
}
fmt.Println("Home email:", homeEmail)
// Output: Home email: jane.doe@example.com
}Filtrado de Observations por Estado
bundle := []byte(`{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"resource": {
"resourceType": "Observation",
"id": "obs-1",
"status": "final",
"code": {"coding": [{"system": "http://loinc.org", "code": "2339-0", "display": "Glucose"}]},
"valueQuantity": {"value": 95, "unit": "mg/dL"}
}
},
{
"resource": {
"resourceType": "Observation",
"id": "obs-2",
"status": "preliminary",
"code": {"coding": [{"system": "http://loinc.org", "code": "2339-0", "display": "Glucose"}]},
"valueQuantity": {"value": 110, "unit": "mg/dL"}
}
},
{
"resource": {
"resourceType": "Observation",
"id": "obs-3",
"status": "final",
"code": {"coding": [{"system": "http://loinc.org", "code": "6299-2", "display": "Urea nitrogen"}]},
"valueQuantity": {"value": 18, "unit": "mg/dL"}
}
}
]
}`)
// Get only final observations
finalIDs, err := fhirpath.EvaluateToStrings(bundle,
"Bundle.entry.resource.where(status = 'final').id")
if err != nil {
log.Fatal(err)
}
fmt.Println("Final observation IDs:", finalIDs)
// Output: Final observation IDs: [obs-1 obs-3]Filtrado por Campos Anidados
Puede usar where() con rutas que navegan a objetos hijos:
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-filter-nested",
"name": [
{"use": "official", "family": "Doe", "given": ["Jane"]},
{"use": "maiden", "family": "Smith", "given": ["Jane"]},
{"use": "nickname", "given": ["JD"]}
]
}`)
// Get only names that have a family field
namesWithFamily, err := fhirpath.EvaluateToStrings(patient,
"Patient.name.where(family.exists()).family")
if err != nil {
log.Fatal(err)
}
fmt.Println("Names with family:", namesWithFamily)
// Output: Names with family: [Doe Smith]select() – Proyectar Campos
La función select() evalúa una expresión contra cada elemento y devuelve los resultados recopilados. A diferencia de where() que filtra elementos, select() los transforma.
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-select",
"name": [
{"use": "official", "family": "Martinez", "given": ["Carlos", "Alberto"]},
{"use": "usual", "family": "Martinez", "given": ["Charlie"]}
]
}`)
// Project just the given names from all name entries
givenNames, err := fhirpath.EvaluateToStrings(patient,
"Patient.name.select(given)")
if err != nil {
log.Fatal(err)
}
fmt.Println("All given names:", givenNames)
// Output: All given names: [Carlos Alberto Charlie]
// Project the family name from each entry
families, err := fhirpath.EvaluateToStrings(patient,
"Patient.name.select(family)")
if err != nil {
log.Fatal(err)
}
fmt.Println("Families:", families)
// Output: Families: [Martinez Martinez]exists() – Verificar Presencia
La función exists() devuelve true si la colección contiene al menos un elemento. Con un argumento de criterio, devuelve true si algún elemento coincide.
Verificaciones Básicas de Existencia
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-exists",
"active": true,
"name": [{"family": "Thompson", "given": ["Sarah"]}],
"telecom": [
{"system": "phone", "value": "555-1234"}
]
}`)
// Does the patient have a name?
hasName, err := fhirpath.EvaluateToBoolean(patient, "Patient.name.exists()")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has name:", hasName)
// Output: Has name: true
// Does the patient have a deceased indicator?
hasDeceased, err := fhirpath.EvaluateToBoolean(patient, "Patient.deceased.exists()")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has deceased:", hasDeceased)
// Output: Has deceased: false
// Using the Exists convenience function
hasPhone, err := fhirpath.Exists(patient, "Patient.telecom.where(system = 'phone')")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has phone:", hasPhone)
// Output: Has phone: trueExistencia con Criterio
Cuando pasa un criterio a exists(), verifica si algún elemento de la colección satisface esa condición:
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-exists-criteria",
"name": [
{"use": "official", "family": "Lee", "given": ["David"]},
{"use": "nickname", "given": ["Dave"]}
],
"telecom": [
{"system": "phone", "value": "555-0001", "use": "home"},
{"system": "email", "value": "dave@example.com", "use": "work"}
]
}`)
// Does any name have "use = official"?
hasOfficial, err := fhirpath.EvaluateToBoolean(patient,
"Patient.name.exists(use = 'official')")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has official name:", hasOfficial)
// Output: Has official name: true
// Is there a work email?
hasWorkEmail, err := fhirpath.EvaluateToBoolean(patient,
"Patient.telecom.exists(system = 'email' and use = 'work')")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has work email:", hasWorkEmail)
// Output: Has work email: truecount() – Contar Elementos
La función count() (y su wrapper de conveniencia en Go) devuelve el número de elementos en una colección.
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-count",
"identifier": [
{"system": "http://hospital.example.org/mrn", "value": "MRN-001"},
{"system": "http://hl7.org/fhir/sid/us-ssn", "value": "999-99-1234"},
{"system": "http://hospital.example.org/mrn", "value": "MRN-002"}
],
"name": [
{"use": "official", "family": "Brown", "given": ["Alice", "Marie"]},
{"use": "maiden", "family": "Green"}
],
"address": [
{"use": "home", "city": "Portland"},
{"use": "work", "city": "Seattle"}
]
}`)
// Count identifiers
idCount, err := fhirpath.Count(patient, "Patient.identifier")
if err != nil {
log.Fatal(err)
}
fmt.Println("Identifiers:", idCount)
// Output: Identifiers: 3
// Count names using the FHIRPath function
result, err := fhirpath.Evaluate(patient, "Patient.name.count()")
if err != nil {
log.Fatal(err)
}
fmt.Println("Name count:", result)
// Output: Name count: [2]
// Count all given names across all name entries
givenCount, err := fhirpath.Count(patient, "Patient.name.given")
if err != nil {
log.Fatal(err)
}
fmt.Println("Total given names:", givenCount)
// Output: Total given names: 3empty() – Verificar Vacío
La función empty() devuelve true cuando la colección tiene cero elementos. Es el inverso lógico de exists().
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-empty",
"name": [{"family": "Wilson"}],
"telecom": []
}`)
// Is the name collection empty?
nameEmpty, err := fhirpath.EvaluateToBoolean(patient, "Patient.name.empty()")
if err != nil {
log.Fatal(err)
}
fmt.Println("Name is empty:", nameEmpty)
// Output: Name is empty: false
// Is the deceased field empty (not present)?
deceasedEmpty, err := fhirpath.EvaluateToBoolean(patient, "Patient.deceased.empty()")
if err != nil {
log.Fatal(err)
}
fmt.Println("Deceased is empty:", deceasedEmpty)
// Output: Deceased is empty: trueCombinación de Filtros
Puede encadenar funciones de filtrado para construir consultas poderosas.
Encadenamiento de Llamadas where()
encounter := []byte(`{
"resourceType": "Encounter",
"id": "enc-combined",
"status": "finished",
"class": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code": "IMP"
},
"participant": [
{
"type": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType", "code": "ATND"}]}],
"individual": {"reference": "Practitioner/pract-1", "display": "Dr. Smith"}
},
{
"type": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType", "code": "CON"}]}],
"individual": {"reference": "Practitioner/pract-2", "display": "Dr. Jones"}
},
{
"type": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType", "code": "ATND"}]}],
"individual": {"reference": "Practitioner/pract-3", "display": "Dr. Williams"}
}
]
}`)
// Get attending practitioners only
attendingNames, err := fhirpath.EvaluateToStrings(encounter,
"Encounter.participant.where(type.coding.code = 'ATND').individual.display")
if err != nil {
log.Fatal(err)
}
fmt.Println("Attending:", attendingNames)
// Output: Attending: [Dr. Smith Dr. Williams]
// Count attending practitioners
attendingCount, err := fhirpath.Count(encounter,
"Encounter.participant.where(type.coding.code = 'ATND')")
if err != nil {
log.Fatal(err)
}
fmt.Println("Attending count:", attendingCount)
// Output: Attending count: 2Combinación de exists() y where()
medicationRequest := []byte(`{
"resourceType": "MedicationRequest",
"id": "medreq-1",
"status": "active",
"intent": "order",
"medicationCodeableConcept": {
"coding": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"code": "1049502",
"display": "Acetaminophen 325 MG Oral Tablet"
}
]
},
"dosageInstruction": [
{
"timing": {
"repeat": {
"frequency": 1,
"period": 6,
"periodUnit": "h"
}
},
"route": {
"coding": [{"system": "http://snomed.info/sct", "code": "26643006", "display": "Oral route"}]
},
"doseAndRate": [
{
"doseQuantity": {
"value": 2,
"unit": "tablets",
"system": "http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm",
"code": "TAB"
}
}
]
}
]
}`)
// Check if the medication is active
isActive, err := fhirpath.EvaluateToBoolean(medicationRequest,
"MedicationRequest.status = 'active'")
if err != nil {
log.Fatal(err)
}
fmt.Println("Is active:", isActive)
// Output: Is active: true
// Check if dosage instructions exist
hasDosage, err := fhirpath.Exists(medicationRequest,
"MedicationRequest.dosageInstruction")
if err != nil {
log.Fatal(err)
}
fmt.Println("Has dosage:", hasDosage)
// Output: Has dosage: true
// Get the medication display
medName, err := fhirpath.EvaluateToString(medicationRequest,
"MedicationRequest.medicationCodeableConcept.coding.display")
if err != nil {
log.Fatal(err)
}
fmt.Println("Medication:", medName)
// Output: Medication: Acetaminophen 325 MG Oral TabletEjemplo Completo Funcional
Un programa autónomo que muestra todas las funciones de filtrado juntas:
package main
import (
"fmt"
"log"
"github.com/gofhir/fhirpath"
)
func main() {
patient := []byte(`{
"resourceType": "Patient",
"id": "pat-comprehensive",
"active": true,
"name": [
{"use": "official", "family": "Garcia", "given": ["Maria", "Isabel"]},
{"use": "nickname", "given": ["Isa"]}
],
"telecom": [
{"system": "phone", "value": "+1-555-0100", "use": "mobile"},
{"system": "phone", "value": "+1-555-0101", "use": "work"},
{"system": "email", "value": "maria.garcia@example.com", "use": "home"},
{"system": "email", "value": "m.garcia@hospital.org", "use": "work"}
],
"address": [
{"use": "home", "city": "Austin", "state": "TX"},
{"use": "work", "city": "Houston", "state": "TX"}
],
"identifier": [
{"system": "http://hospital.example.org/mrn", "value": "MRN-54321"},
{"system": "http://hl7.org/fhir/sid/us-ssn", "value": "123-45-6789"}
]
}`)
// where() -- filter telecom by system
phones, _ := fhirpath.EvaluateToStrings(patient,
"Patient.telecom.where(system = 'phone').value")
fmt.Println("Phone numbers:", phones)
// where() with compound condition
workEmail, _ := fhirpath.EvaluateToString(patient,
"Patient.telecom.where(system = 'email' and use = 'work').value")
fmt.Println("Work email: ", workEmail)
// select() -- project given names
allGiven, _ := fhirpath.EvaluateToStrings(patient,
"Patient.name.select(given)")
fmt.Println("All given: ", allGiven)
// exists() -- presence check
hasNickname, _ := fhirpath.EvaluateToBoolean(patient,
"Patient.name.exists(use = 'nickname')")
fmt.Println("Has nickname: ", hasNickname)
// count() -- element count
telecomCount, _ := fhirpath.Count(patient, "Patient.telecom")
fmt.Println("Telecom count:", telecomCount)
// empty() -- absence check
noPhoto, _ := fhirpath.EvaluateToBoolean(patient, "Patient.photo.empty()")
fmt.Println("No photo: ", noPhoto)
// Combined: count phones only
phoneCount, _ := fhirpath.Count(patient,
"Patient.telecom.where(system = 'phone')")
fmt.Println("Phone count: ", phoneCount)
// Combined: official family + existence guard
officialFamily, err := fhirpath.EvaluateToString(patient,
"Patient.name.where(use = 'official').family")
if err != nil {
log.Fatal(err)
}
fmt.Println("Official name:", officialFamily)
}