Skip to content

Converting Repeating HL7 Segments to a JSON Array

The mirror of Converting a JSON Array to Repeating HL7 Segments: take a repeating segment in an HL7 source (ORC, OBX, DG1, …) and emit one JSON array element per segment on the outbound message.

Two building blocks:

  • source.getCount('ORC'). Number of ORC repeats in the source.
  • message.addObjectToJSONArray('/orders', obj). Appends obj to the JSON array at /orders, creating the array if it does not yet exist.

Use qie.parseJSONString('{}') to construct a fresh empty object per iteration, fill it with the segment's field values, and append it.

// Set the outer wrapper first.
message.setNode('/patient/mrn',         source.getNode('PID-3.1'));
message.setNode('/patient/name/family', source.getNode('PID-5.1'));
message.setNode('/patient/name/given',  source.getNode('PID-5.2'));

// One JSON object per ORC repetition.
var orderCount = source.getCount('ORC');
for (var i = 1; i <= orderCount; i++) {
    var order = qie.parseJSONString('{}');
    order.setNode('/orderId',            source.getNode('ORC-2.1', i));
    order.setNode('/orderStatus',        source.getNode('ORC-5',   i));
    order.setNode('/placingProviderNpi', source.getNode('ORC-12.1', i));
    message.addObjectToJSONArray('/orders', order);
}

addObjectToJSONArray creates the target array on first call, so there is no need to setJSONArray('/orders') up front, but doing so keeps the wrapper's shape obvious when the loop count is zero.

Nested arrays

For HL7 sibling relationships like ORC → OBR → OBX where each order carries a list of observations, the cleanest approach is to configure the source's Group By setting to the outer segment (e.g. ORC). QIE then spawns one message per ORC group, and each invocation of this mapping sees only the OBR / OBX segments that belong to the current ORC. source.getCount('OBX') returns the count within that group rather than across the whole batch.

// One incoming message per ORC group (source is Group By = ORC).
var order = qie.parseJSONString('{}');
order.setNode('/orderId', source.getNode('ORC-2.1'));

order.setJSONArray('/observations');
var obxCount = source.getCount('OBX');
for (var j = 1; j <= obxCount; j++) {
    var obs = qie.parseJSONString('{}');
    obs.setNode('/observationId', source.getNode('OBX-3.1', j));
    obs.setNode('/value',         source.getNode('OBX-5',   j));
    obs.setNode('/units',         source.getNode('OBX-6.1', j));
    order.addObjectToJSONArray('/observations', obs);
}

message.addObjectToJSONArray('/orders', order);

This produces one outbound JSON message per ORC group. To collapse them into a single JSON message with all orders in one /orders array, chain the ORC-grouped stage into a downstream channel that accumulates them via qie.spawnNewMessage and a per-batch cache. See Splitting One Message into Many for the split direction and Building a New Output Message for accumulation patterns.

Controlling JSON value types

A value read from a message is a string, and setNode writes it as a JSON string. That is usually what you want: an MRN or account number keeps its leading zeros without any special handling. Reach for a typed setter when the output needs a real JSON number or boolean instead. See Value Types on a Write for the full rules.

Force the type explicitly with setJSONString, setJSONNumber, or setJSONBoolean:

var order = qie.parseJSONString('{}');
order.setJSONString('/mrn',           source.getNode('PID-3.1'));     // explicit, though setNode would also keep it a string
order.setJSONNumber('/orderQuantity', source.getNode('ORC-7.1', i));  // "5" becomes 5, not "5"
order.setJSONBoolean('/isPriority',   source.getNode('ORC-7.5', i));  // "true"/"false" becomes true/false

The typed setters take the same (path, value, instance) signature family as setNode, so they slot in wherever setNode was being used.