Read patient, visit and message details
This guide reads the fields most integrations start with: who the patient is, where they are, and what kind of message arrived. Every example parses the same synthetic admission message.
Read the patient
msg.patient reads the PID segment. It is undefined when the message has no PID, so use ?..
import { parseHL7 } from "@cosyte/hl7";
const raw = [
"MSH|^~\\&|CLINIC|MAIN|LAB|REF|20250102153045-0500||ADT^A01^ADT_A01|MSG00001|P|2.5",
"EVN|A01|20250102153045",
"PID|1||MRN12345^^^HOSP^MR||Smith^Jane^Q||19800115|F|||123 Main St^^Springfield^IL^62701||^PRN^PH^^^217^5550147",
"PV1|1|I|ICU^101^A^MAIN||||1234^Welby^Marcus^^^^MD||||||||||||VISIT001",
].join("\r");
const patient = parseHL7(raw).patient;
patient?.mrn; // => "MRN12345"
patient?.fullName; // => "Jane Q Smith"
patient?.familyName; // => "Smith"
patient?.sex; // => "F"
patient?.dateOfBirth?.raw; // => "19800115"
patient?.dateOfBirth?.precision; // => "day"
patient?.address?.city; // => "Springfield"
patient?.address?.zipOrPostalCode; // => "62701"
patient?.identifiers.length; // => 1
mrn is the first PID-3 identifier whose type code is MR, or the first identifier when none
is typed MR; identifiers is every PID-3 repetition as a CX composite, always present and
possibly empty. A birth date is a fidelity TS
that keeps the precision the sender wrote, never a Date (see
Read dates and times).
Read the visit
msg.visit reads PV1, and is undefined when the message has none (most results and orders).
location is a PL composite; the doctors are XCN composites.
import { parseHL7 } from "@cosyte/hl7";
const raw = [
"MSH|^~\\&|CLINIC|MAIN|LAB|REF|20250102153045-0500||ADT^A01^ADT_A01|MSG00001|P|2.5",
"PID|1||MRN12345^^^HOSP^MR||Smith^Jane^Q||19800115|F",
"PV1|1|I|ICU^101^A^MAIN||||1234^Welby^Marcus^^^^MD||||||||||||VISIT001",
].join("\r");
const visit = parseHL7(raw).visit;
visit?.patientClass; // => "I"
visit?.location?.pointOfCare; // => "ICU"
visit?.location?.room; // => "101"
visit?.location?.bed; // => "A"
visit?.location?.facility?.namespaceId; // => "MAIN"
visit?.attendingDoctor?.familyName; // => "Welby"
visit?.visitNumber; // => "VISIT001"
Read what kind of message it is
msg.meta reads the MSH header, with MSH-9 already split into its three components. Branch on
messageCode and triggerEvent rather than on type: some senders fill MSH-9.3 and some do not,
and type carries it when they do.
import { parseHL7 } from "@cosyte/hl7";
const raw =
"MSH|^~\\&|CLINIC|MAIN|LAB|REF|20250102153045-0500||ADT^A01^ADT_A01|MSG00001|P|2.5\r" +
"PID|1||MRN12345^^^HOSP^MR||Smith^Jane^Q";
const meta = parseHL7(raw).meta;
meta.type; // => "ADT^A01^ADT_A01"
meta.messageCode; // => "ADT"
meta.triggerEvent; // => "A01"
meta.messageStructure; // => "ADT_A01"
meta.controlId; // => "MSG00001"
meta.sendingApp; // => "CLINIC"
meta.version; // => "2.5"
meta.timestamp?.offsetMinutes; // => -300
Narrow a message to its type
msg.is("ADT^A01") makes the same comparison and tells the compiler the answer. Inside the guard
the message code and trigger event are literal types, and part and parts accept only the
segments that message type's published structure requires.
import { parseHL7 } from "@cosyte/hl7";
const raw =
"MSH|^~\\&|CLINIC|MAIN|LAB|REF|20250102153045||ADT^A01^ADT_A01|MSG00001|P|2.5\r" +
"EVN|A01|20250102153045\r" +
"PID|1||MRN12345^^^HOSP^MR||Smith^Jane^Q";
const msg = parseHL7(raw);
msg.is("ADT^A01"); // => true
msg.is("ADT^A01^ADT_A01"); // => false
if (msg.is("ADT^A01")) {
const code: "ADT" = msg.meta.messageCode; // a literal type, no longer optional
code; // => "ADT"
msg.part("PID")?.field(3).value; // => "MRN12345"
msg.parts("EVN").length; // => 1
// msg.part("OBX"); // does not compile: ADT^A01 does not require OBX
msg.segments("OBX").length; // => 0
}
A key is "<MSH-9.1>^<MSH-9.2>", or the message code alone for a type the published structures
match on the code alone ("ACK"). SUPPORTED_OVERLAY_MESSAGES lists every key. Any other string,
including the three-component form, returns false and never throws.
Narrowing does not promise presence. An ADT^A01 that arrives without its PID still answers
true: part returns undefined and parts an empty list, as segments does, and the absence
shows on msg.structure (see Validate a message).
Read a field no helper covers
A dot-path reaches any field, component or subcomponent: SEGMENT.field.component.subcomponent,
numbered from 1 as the standard numbers them. A bracketed index counts from 0.
import { parseHL7 } from "@cosyte/hl7";
const raw = [
"MSH|^~\\&|CLINIC|MAIN|LAB|REF|20250102153045||ADT^A01|MSG00001|P|2.5",
"PID|1||MRN12345^^^HOSP^MR~XYZ987^^^STATE^SS||Smith^Jane^Q",
"NK1|1|Smith^John|SPO",
"NK1|2|Smith^Ann|DAU",
].join("\r");
const msg = parseHL7(raw);
msg.get("PID.5.1"); // => "Smith"
msg.get("PID.5.2"); // => "Jane"
msg.get("PID.3[1].1"); // => "XYZ987"
msg.get("NK1[1].2.2"); // => "Ann"
msg.getAll("NK1").length; // => 2
The three ways to read a message explains when to reach for a dot-path or for the segment tree instead of a helper.