Announcement

Collapse
No announcement yet.

Generating multiple segments in outbound messages

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Generating multiple segments in outbound messages

    I have been trying to create an Outbound HL7 message with multiple segments for Next of kin, Allergies, and Insurance companies from my MS SQL database. I have created a channel that uses source message builder type transformers to map my database fields to my HL7 Template. This works fine, but I can only map one next of kin, one allergy, and one insurance company per patient. I would like to know how to support multiple segments in my outbound message if the number of segments is different for each patient.

    One thought I had was to create a javascript source transformer that queries the database for the detail next of kin, allergy, and insurance information and then write a segment directly to the output. Is there a better way to do this? if so, how? I have not found any examples of outbound channels that do this, only inbound. Any suggestions about how this is supposed to work would be appreciated.

    If it is possible to to this, do I need to change all my message builder transforms to use javascript or can I use a combination of javascript, mapper, and message builder types? If so, how do I know which transformer runs first, second...? Also, How can I write directly to the output of the channel via javascript? Or should the template be modified on the fly to allow various segment formats?

  • #2
    Re:Generating multiple segments in outbound messag

    It is very good and important question. I've tried some JS codes but without success.
    Is it possible to modify template or add additional segments to outbound HL7 message?

    -Mark

    Comment


    • #3
      Re:Generating multiple segments in outbound messag

      Please check out the E4X tutorial stickied in the other forums. Also, search Google for E4X examples - any E4X can be used to build the outgoing message or inbound.

      To add 10 new segments:
      Code:
      var obx = msg['OBX']; //this could be tmp instead for the outgoing template
      for (var i = 0; i < 10; i++){
         msg['OBX'][i] = obx;
         //copies the obx to a new repeating segment. You can now modify msg['OBX'][i] directly
      }
      You do not have to copy the original OBX first, you could just use XML directly:
      Code:
      for (var i = 0; i < 10; i++){
         msg['OBX'][i] = "<OBX><OBX.5><OBX.5.1>Test</OBX.5.1></OBX.5></OBX>"; //psuedo code - might need to be adjusted
      }
      Chris Lang

      Comment


      • #4
        Re:Generating multiple segments in outbound messag

        Thank you for that. It is very useful.

        Comment


        • #5
          Re:Generating multiple segments in outbound messages

          Hi all,

          I was working on the same problem this week and finally got the following JS code to work. I am converting database queries to HL7 and dumping to a file (to be read later by GE Centricity). I needed to add a second A04 IN1 segment if there was any secondary insurance for the patient. Since the A04 always has a default single IN1 seqment, the following script just copies it, renumbers it (= 2) and inserts the secondary ins. patient ID number into field 49. That's all I need it to do.


          //add a second IN1 segment if db query variable 'ins_grp_2' not null
          var ins2 = msg['ins_code_no_2'].toString()
          if (ins2.length > 0) { //tests for presence of incoming message data

          var ins = tmp['IN1'];
          for (var i = 0; i < 2; i++){
          tmp['IN1'][i] = ins; //copies the IN1 to a new repeating segment.

          }
          tmp['IN1'][1]['IN1.1']['IN1.1.1']= 2;
          tmp['IN1'][1]['IN1.49']['IN1.49.1']= ins2;
          }

          I'm sure there are cleaner ways to do it. Hope it helps.
          Paul69

          Comment


          • #6
            Re:Generating multiple segments in outbound messag

            What was not obvious for me is that msg and tmp objects are in fact XML objects and all statements like
            Code:
            tmp['IN1'][1]['IN1.49']['IN1.49.1']
            are E4X statements.

            Code example from previous replies should not have "
            Code:
            for (var i = 0; i < 10; i++){
               msg['OBX'][i] = <OBX><OBX.5><OBX.5.1>Test</OBX.5.1></OBX.5></OBX>; //no " signs
            }

            Comment


            • #7
              Re:Generating multiple segments in outbound messag

              Thanks to all who have answered my questions. I have successfully created HL7 outbound messages from my MSSQL database. I created some views that give me the main patient information with keys to other tables with related information such as next of kin, Insurance, and allergies. I then used several java transformer steps to create multiple segments when needed for Insurance, Next of kin and Allergies. A typical step looks like this:
              Code:
              var driver = "net.sourceforge.jtds.jdbc.Driver";
              var address = "jdbc:jtds:«»sqlserver://luke1:1433/CPR_MSAOM_LOCAL";
              var username = "user"; 
              var password = "password"; 
              var nk1 = tmp['NK1'];
              var i = 0;
              
              // Open a connection to the SQL server and query CPR+ for Contacts.
              var dbConn = DatabaseConnectionFactory.createDatabaseConnection(driver,address,username,password);
              var Query = "Select [MRN],[LNAME],[FNAME],[LINKTYPE],[TITLE],[ADDRESS],[CITY],[ST],[ZIP],[PHONE1],[PHONE2] From HL7_NK1 Where MRN = "+msg['cpk_hr'].toString();
              var cNK1 = dbConn.executeCachedQuery(Query);
              
              while (cNK1.next() != '0') {
              
                  tmp['NK1'][i] = nk1;	// Copy a blank NK1 record into the template
                  // Load the current record's contents into the template.
              
                  tmp['NK1'][i]['NK1.1'] = i + 1;			// load Set ID for segment
                  tmp['NK1'][i]['NK1.2']['PN.1'] = cNK1.getString(2);	//Last Name
                  tmp['NK1'][i]['NK1.2']['PN.2'] = cNK1.getString(3); //First Name
                  tmp['NK1'][i]['NK1.3']['CE.1'] = cNK1.getString(4); //LinkType
                  tmp['NK1'][i]['NK1.3']['CE.2'] = cNK1.getString(5); //Title
                  tmp['NK1'][i]['NK1.4']['AD.1'] = cNK1.getString(6); //Address
                  tmp['NK1'][i]['NK1.4']['AD.3'] = cNK1.getString(7); //City
                  tmp['NK1'][i]['NK1.4']['AD.4'] = cNK1.getString(8); //State
                  tmp['NK1'][i]['NK1.4']['AD.5'] = cNK1.getString(9); //Zip
                  tmp['NK1'][i]['NK1.5'] = cNK1.getString(10);	//Phone1
                  tmp['NK1'][i]['NK1.6'] = cNK1.getString(11);	//Phone2
              
                  i++;	// Attempt to load another Contact.
              }
              if (i == 0)
              {
                  delete tmp['NK1'];
              }
              cNK1.close();
              dbConn.close();
              This works pretty well, but I have had some problems. One is the delete tmp['NK1']; statement in the "if" at the end of the while loop. In order to get the step to always work without an "Cannot set property NK1.1 of undefined to 6" error message, I have had to add an NK1 line to the template and then delete it if there are no next of kin records found. I know there is another way to do this, but I always get an error if I do not have a line in the outgoing template. I have the same error for each of the java transformer step segments IN1, NK1 and AL1. I have seen code like:
              Code:
              var obx = tmp['ORU_R01.RESPONSE']['ORU_R01.ORDER_OBSERVATION']['ORU_R01.OBSERVATION'][0]
              but I am not sure where this comes from. I'm sure I could remove the delete code if I knew.

              If anyone has any suggestions, I would love to hear them.

              Comment


              • #8
                Re:Generating multiple segments in outbound messag

                This is one way to resolve the "Cannot set property OBX of undefined to 6" error message...

                I have a situation where I need to add Height and Weight only when Admitted (A01). I added in a place holder (OBX||||||) into the outgoing data template so adding multiple segments works correctly, then added a delete so it would remove that segment for all other messages.

                Code:
                if (HL7EventCode=="A01"«»)
                    {
                    var i = 0;
                    tmp['OBX'][i] = obx;
                	
                    tmp['OBX'][i]['OBX.2']['OBX.2.1']="ST";
                    tmp['OBX'][i]['OBX.3']="3141-9^WEIGHT^LOINC";
                    tmp['OBX'][i]['OBX.5']['OBX.5.1']=Weight;
                    tmp['OBX'][i]['OBX.6']['OBX.6.1']="kg";
                    tmp['OBX'][i]['OBX.11']['OBX.11.1']="F";
                
                    i++;
                    tmp['OBX'][i] = obx;
                
                    tmp['OBX'][i]['OBX.2']['OBX.2.1']="ST";
                    tmp['OBX'][i]['OBX.3']="3137-7^HEIGHT^LOINC";
                    tmp['OBX'][i]['OBX.5']['OBX.5.1']=Height;
                    tmp['OBX'][i]['OBX.6']['OBX.6.1']="cm";
                    tmp['OBX'][i]['OBX.11']['OBX.11.1']="F";
                    }
                else
                    {
                    // Must put OBX|||||| in the outgoing data template then delete it if it is not needed
                    delete tmp['OBX'];
                    }
                Regards,
                John Lehew

                Post edited by: jlehew, at: 10/17/2007 14:22

                Comment


                • #9
                  Re:Generating multiple segments in outbound messag

                  Thank you. That is a good idea.

                  Comment


                  • #10
                    Re:Generating multiple segments in outbound messag

                    I hate to drag up a dead thread, but I just wanted to thank eisenbrl for posting this. The approach outlined here works great.

                    Thanks eisenbrl!!!

                    Comment


                    • #11
                      Is this still the best way to insert a repeating segment such as IN1 into an outbound message? I'm asking this since this thread is kind of old. I am using the latest version of Mirth.

                      Thanks

                      Craig

                      Comment


                      • #12
                        Originally posted by eisenbrl View Post
                        Thanks to all who have answered my questions. I have successfully created HL7 outbound messages from my MSSQL database. I created some views that give me the main patient information with keys to other tables with related information such as next of kin, Insurance, and allergies. I then used several java transformer steps to create multiple segments when needed for Insurance, Next of kin and Allergies. A typical step looks like this:
                        Code:
                        var driver = "net.sourceforge.jtds.jdbc.Driver";
                        var address = "jdbc:jtds:«»sqlserver://luke1:1433/CPR_MSAOM_LOCAL";
                        var username = "user"; 
                        var password = "password"; 
                        var nk1 = tmp['NK1'];
                        var i = 0;
                        
                        // Open a connection to the SQL server and query CPR+ for Contacts.
                        var dbConn = DatabaseConnectionFactory.createDatabaseConnection(driver,address,username,password);
                        var Query = "Select [MRN],[LNAME],[FNAME],[LINKTYPE],[TITLE],[ADDRESS],[CITY],[ST],[ZIP],[PHONE1],[PHONE2] From HL7_NK1 Where MRN = "+msg['cpk_hr'].toString();
                        var cNK1 = dbConn.executeCachedQuery(Query);
                        
                        while (cNK1.next() != '0') {
                        
                            tmp['NK1'][i] = nk1;	// Copy a blank NK1 record into the template
                            // Load the current record's contents into the template.
                        
                            tmp['NK1'][i]['NK1.1'] = i + 1;			// load Set ID for segment
                            tmp['NK1'][i]['NK1.2']['PN.1'] = cNK1.getString(2);	//Last Name
                            tmp['NK1'][i]['NK1.2']['PN.2'] = cNK1.getString(3); //First Name
                            tmp['NK1'][i]['NK1.3']['CE.1'] = cNK1.getString(4); //LinkType
                            tmp['NK1'][i]['NK1.3']['CE.2'] = cNK1.getString(5); //Title
                            tmp['NK1'][i]['NK1.4']['AD.1'] = cNK1.getString(6); //Address
                            tmp['NK1'][i]['NK1.4']['AD.3'] = cNK1.getString(7); //City
                            tmp['NK1'][i]['NK1.4']['AD.4'] = cNK1.getString(8); //State
                            tmp['NK1'][i]['NK1.4']['AD.5'] = cNK1.getString(9); //Zip
                            tmp['NK1'][i]['NK1.5'] = cNK1.getString(10);	//Phone1
                            tmp['NK1'][i]['NK1.6'] = cNK1.getString(11);	//Phone2
                        
                            i++;	// Attempt to load another Contact.
                        }
                        if (i == 0)
                        {
                            delete tmp['NK1'];
                        }
                        cNK1.close();
                        dbConn.close();
                        This works pretty well, but I have had some problems. One is the delete tmp['NK1']; statement in the "if" at the end of the while loop. In order to get the step to always work without an "Cannot set property NK1.1 of undefined to 6" error message, I have had to add an NK1 line to the template and then delete it if there are no next of kin records found. I know there is another way to do this, but I always get an error if I do not have a line in the outgoing template. I have the same error for each of the java transformer step segments IN1, NK1 and AL1. I have seen code like:
                        Code:
                        var obx = tmp['ORU_R01.RESPONSE']['ORU_R01.ORDER_OBSERVATION']['ORU_R01.OBSERVATION'][0]
                        but I am not sure where this comes from. I'm sure I could remove the delete code if I knew.

                        If anyone has any suggestions, I would love to hear them.
                        This is a great post, however, I still have some beginner questions on how to make this work. It this all done as a source transformer step? What is the Source channel type in that case? I'm currently using DatabaseReader but it will not let me have an empty query. I don't want a select at the source and then duplicate it in the transformer do I? Seems inefficient.

                        What about the update step? Should it be done in the Transformer JS or still at the Source setup?

                        I have the seemingly basic need to query a database for a set of rows that need combining into one HL7 file with multiple OBX segments. The select will return multiple patients so I will need to break and start a new HL7 file for each one. Is there a "best" way to accomplish this in Mirth?

                        Comment


                        • #13
                          Originally posted by luv2hike View Post
                          This is a great post, however, I still have some beginner questions on how to make this work. It this all done as a source transformer step? What is the Source channel type in that case? I'm currently using DatabaseReader but it will not let me have an empty query. I don't want a select at the source and then duplicate it in the transformer do I? Seems inefficient.

                          What about the update step? Should it be done in the Transformer JS or still at the Source setup?

                          I have the seemingly basic need to query a database for a set of rows that need combining into one HL7 file with multiple OBX segments. The select will return multiple patients so I will need to break and start a new HL7 file for each one. Is there a "best" way to accomplish this in Mirth?
                          Is there anyway to modify your query so it only picks up one patient at a time? That is what we suggest.
                          -Brad

                          Comment


                          • #14
                            Originally posted by bradd View Post
                            Is there anyway to modify your query so it only picks up one patient at a time? That is what we suggest.
                            -Brad
                            Yes, I just figured that out. It requires 2 queries. One in the source definition to get a list of just the patients. Then in my source transformer, I query all entries for just the current patient and loop through each result building an OBX segment for each one. Then the transformer marks the records for the patient as exported so they are not picked up again. I was unable to do this in the On-Update field for the source as it gave me a warning about multiple rows being updated and it seemed to occur before the transform query got its list of rows.

                            In the source query:
                            Code:
                            select distinct BSEtests.PatientID
                             from TestBSEdx
                             left join BSEtests on TestBSEdx.TestID=BSEtests.BSEtestID
                             left join Patients on BSEtests.PatientID=Patients.PatientID
                             where TestBSEdx.exported=0 order by BSEtests.PatientID;
                            Then in a source transformer:
                            Code:
                            var dbConn = DatabaseConnectionFactory.createDatabaseConnection(
                            	'com.mysql.jdbc.Driver',
                            	'jdbc:mysql://localhost:3306/ionmed',
                            	'user',
                            	'password'
                            );
                            
                            // find all entries for this patient
                            var sql = "select TestBSEdx.TestBSEdxID,"+
                            		  " BSEtests.TestDate,"+
                            		  " BSEcodes.Code"+
                            		  " from TestBSEdx"+
                            		  " left join BSEtests on TestBSEdx.TestID=BSEtests.BSEtestID"+
                            		  " left join BSEcodes on TestBSEdx.BSEdx=BSEcodes.DiagID"+
                            		  " left join Patients on BSEtests.PatientID=Patients.PatientID"+
                            		  " where TestBSEdx.exported = 0 and BSEtests.PatientID = "+msg['patientid'].toString()+
                            		  " order by BSEtests.PatientID, BSEtests.TestDate;";
                            
                            var i = 0;
                            var obx = tmp['OBX'];
                            var results = dbConn.executeCachedQuery(sql);
                            
                            while(results.next()) {
                            	// get new template and fill the fields
                            	tmp['OBX'][i] = obx;
                            	tmp['OBX'][i]['OBX.5']['OBX.5.1'] = results.getString('Code');
                            	tmp['OBX'][i]['OBX.14']['OBX.14.1'] = results.getString('TestDate');
                            // ... more will follow but this is for testing
                            
                            	// increment the counter
                            	i++;
                            }
                            
                            // mark all patient entries as exported
                            sql = "update TestBSEdx"+
                            	  " left join BSEtests on TestBSEdx.TestID=BSEtests.BSEtestID"+
                            	  " set exported=1"+
                            	  " where PatientID="+msg['patientid'].toString()+";";
                            dbConn.executeUpdate(sql);
                            
                            dbConn.close();
                            And the "Run-On Update Statement" is set to No.

                            Comment


                            • #15
                              Hi:

                              When I try the above example, I get an error:


                              Code:
                              ERROR-300: Transformer error
                              ERROR MESSAGE:	Error evaluating transformer
                              com.mirth.connect.server.MirthJavascriptTransformerException: 
                              CHANNEL:	0 -  Test FileWriter
                              CONNECTOR:	sourceConnector
                              SCRIPT SOURCE:	
                              SOURCE CODE:	
                              234: {
                              235:    outputStrings[currentLine] = outputStrings[currentLine] + tempString;
                              236:    currentLine++;
                              237: }
                              238: 
                              239: var obx = tmp['OBX'];
                              240: if (outputStrings.length > 0)
                              241: {
                              242:    for (i = 0; i < currentLine; i++)
                              243:    {
                              LINE NUMBER:	239
                              DETAILS:	ReferenceError: "tmp" is not defined.
                              	at com.mirth.connect.server.mule.transformers.JavaScriptTransformer.evaluateScript(JavaScriptTransformer.java:398)
                              	at com.mirth.connect.server.mule.transformers.JavaScriptTransformer.transform(JavaScriptTransformer.java:296)
                              	at org.mule.transformers.AbstractEventAwareTransformer.doTransform(AbstractEventAwareTransformer.java:48)
                              	at org.mule.transformers.AbstractTransformer.transform(AbstractTransformer.java:197)
                              	at org.mule.transformers.AbstractTransformer.transform(AbstractTransformer.java:200)
                              	at org.mule.impl.MuleEvent.getTransformedMessage(MuleEvent.java:251)
                              	at org.mule.routing.inbound.SelectiveConsumer.isMatch(SelectiveConsumer.java:61)
                              	at org.mule.routing.inbound.InboundMessageRouter.route(InboundMessageRouter.java:79)
                              	at org.mule.providers.AbstractMessageReceiver$DefaultInternalMessageListener.onMessage(AbstractMessageReceiver.java:487)
                              	at org.mule.providers.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:266)
                              	at org.mule.providers.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:225)
                              	at com.mirth.connect.connectors.vm.VMMessageReceiver.getMessages(VMMessageReceiver.java:223)
                              	at org.mule.providers.TransactedPollingMessageReceiver.poll(TransactedPollingMessageReceiver.java:108)
                              	at org.mule.providers.PollingMessageReceiver.run(PollingMessageReceiver.java:97)
                              	at org.mule.impl.work.WorkerContext.run(WorkerContext.java:290)
                              	at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
                              	at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:575)
                              	at java.lang.Thread.run(Unknown Source)
                              Does anyone know why?

                              Thank you very much,
                              Robert

                              Comment

                              Working...
                              X