Request for assistance with a FOREACH problem.

Clovertech Forums Read Only Archives Cloverleaf Tcl Library Request for assistance with a FOREACH problem.

  • Creator
    Topic
  • #55135
    Lawrence Nelson
    Participant

      Thanks for reviewing –

      Hoping someone can provide me with the correct information to fix a issue I

      Lawrence Nelson
      System Architect - MaineHealth IT

    Viewing 20 reply threads
    • Author
      Replies
      • #84254

        Is your second foreach supposed to be nested inside of your first one?

        -- Max Drown (Infor)

      • #84255

        If you have a sample TEST message, could you please post it?

        -- Max Drown (Infor)

      • #84256
        Lawrence Nelson
        Participant

          I would say yes – there is a series of ORC’s each has an OBR

          So –

          go into the ORC do each OBR under it

          > then move to the next ORC and do the same until the last OBR is reviewed under the last ORC

          Lawrence Nelson
          System Architect - MaineHealth IT

        • #84257
          Lawrence Nelson
          Participant

            MSH|^~&|LinkLogic-0058|0058002^GOOD HEALTHTGCH|NorDx|GCH|20160714110123||ORM^O01|1784113281899770|P|2.3.1|||NE|NE

            PID|1|650557|259374-0058002||S||||||||||||||||||||||||||||||||||||||

            PV1|1|O|^^^GOOD HEALTHTGCH||||1477693182

            ORC|NW|2516511-5|||||||20160714|||1477693182

            OBR|1|2516511-5||CMPNX^Comp Metabolic Panel (NorDx)|||20160714||1||N|||||1477693182|||||||||||^^^^^R

            NTE|1||Provider[] Lab[X] Collect

            DG1|1||Z78.9^HEALTH MAINTENANCE, ROUTINE^I10^V70.0^HEALTH MAINTENANCE, ROUTINE^I9

            ORC|NW|2516511-6|||||||20160714|||1477693182

            OBR|1|2516511-6||CBCD^CBC with Diff (NorDx)|||20160714||1||N|||||1477693182|||||||||||^^^^^R

            NTE|1||Provider[] Lab[X] Collect

            DG1|1||Z78.9^HEALTH MAINTENANCE, ROUTINE^I10^V70.0^HEALTH MAINTENANCE, ROUTINE^I9

            ORC|NW|2516511-7|||||||20160714|||1477693182

            OBR|1|2516511-7||LPPR1^Lipid Profile (NorDx)|||20160714||1||N|||||1477693182|||||||||||^^^^^R

            NTE|1||Provider[] Lab[X] Collect ~~Please draw regardless of fasting status

            DG1|1||Z78.9^HEALTH MAINTENANCE, ROUTINE^I10^V70.0^HEALTH MAINTENANCE, ROUTINE^I9

            ORC|NW|2516511-8|||||||20160714|||1477693182

            OBR|1|2516511-8||TSH^TSH (NorDx)|||20160714||1||N|||||1477693182|||||||||||^^^^^R

            NTE|1||Provider[] Lab[X] Collect

            DG1|1||Z78.9^HEALTH MAINTENANCE, ROUTINE^I10^V70.0^HEALTH MAINTENANCE, ROUTINE^I9

            Lawrence Nelson
            System Architect - MaineHealth IT

          • #84258

            This would be much easier in an XLATE which is designed to handle looping across messages. Just saying.

            -- Max Drown (Infor)

          • #84259
            Lawrence Nelson
            Participant

              I work at a lab. We have a significant problem with external doctors EMRs submitting duplicate tests on the order choice level – while at the same time they are sending in new messages with the duplicates orders. We are basically taking it out of the provider and EMR’s hands since they have never been able to resolve the problem.

              Cloverleaf has no ‘memory’ on what’s been sent. I’m making one (memory bank of sorts) with a string of data that I’m sending out to an external database table- with more key elements in it than is described with the script I’ve included.

              Lawrence Nelson
              System Architect - MaineHealth IT

            • #84260

              In order to parse through that message, you’ll need to add a bit more code. You’ll probably want to loop across all the segments and use flags to determine where you are in the message (ex. in an OBR segment loop).

              Here’s your code cleaned up a bit for testing.

              set fh [open test_main.hl7 r]; fconfigure $fh -translation binary; set msg [read $fh]; close $fh

              [code]set fh [open test_main.hl7 r]; fconfigure $fh -translation binary; set msg [read $fh]; close $fh

              -- Max Drown (Infor)

            • #84261

              I’m not exactly clear on what your code needs to do based off of the use case you described above.

              Basically every single OBR segment is written to a database and if the database call from the TCL script says it’s a duplicate than that OBR is stricken from the message and reported via email. (again none of this is in what I’ve included). This not something that an XLATE can readily do (my opinion) so I’ve writing this script to put on as a TPS Inbound Data pre-proc to a whole process.

              Do you need to extract all ORC and all OBR segments?

              -- Max Drown (Infor)

            • #84262
              Lawrence Nelson
              Participant

                I need to report all the elements to the table – in the full script OBRs if found to be duplicated are removed.

                Lawrence Nelson
                System Architect - MaineHealth IT

              • #84263

                In your code, this line gets the same set of OBR segments each time, regardless of the parent loop.

                Code:

                set OBRpos [lsearch -all $segList OBR*]

                -- Max Drown (Infor)

              • #84264

                Can you safely use ORC.02 and OBR.02 to relate the ORC segments to the OBR segments?

                -- Max Drown (Infor)

              • #84265

                This seems to work.

                set fh [open test_main.hl7 r]; fconfigure $fh -translation binary; set msg [read $fh]; close $fh

                [code]set fh [open test_main.hl7 r]; fconfigure $fh -translation binary; set msg [read $fh]; close $fh

                -- Max Drown (Infor)

              • #84266
                Lawrence Nelson
                Participant

                  Well that seems to work – but some how it seems like a cheat 🙂

                  When I do the iterates on the xlates for these same messages its not a problem – it really seems like the the message should be able to cascade through the message and report out each OBR as it goes along – and not repeat without have to do what your solution is. NOT THAT I’M NOT GRATEFUL!!

                  Lawrence Nelson
                  System Architect - MaineHealth IT

                • #84267

                  The tcl scripting language is not HL7-aware. It’s just looking at strings.

                  In your case you’re lucky there’s an easy way to create a relationship, or else you’d need a lot more code.

                  I would do this in an xlate and use tcl fragments in the xlate as needed like to write to a database or whatever.

                  -- Max Drown (Infor)

                • #84268
                  Charlie Bursell
                  Participant

                    For you or anyone else using lsearch to extract segments

                    Do not use it like:  set ORCpos [lsearch -all $segList ORC*]

                    Lsearch, by default use glob matching.  That means if the phrase ORC is anywhere in your data you will not get what you expect.  What you want to do is tell lsearch you want every element that starts with ORC

                                    set ORCpos [lsearch -all -regexp $segList {^ORC}]

                    Also a minor point.  You do not need to put your keylget commands inside a catch statement.  A command like keylget args CONTEXT ctx will return 1 if success or 0 if not.  FWIW, if you ever get an error with a command like ‘keylget args CONTEXT” you better get yourself a new engine since this one is really bad  ðŸ˜€

                    I will leave it as an exercise for Max to correct the logic just wanted to insert my $0.02 worth

                  • #84269
                    Lawrence Nelson
                    Participant

                      Hi Charlie – Thanks for the response –

                      Question for you on your comment

                      Yours

                      # set OBR_pos2 [lsearch -all -regexp $segList2 {^OBR}]  

                      >> Your version is also reporting out NTE’s that follow the OBR – why is that

                      Mine

                      set OBR_pos2 [lsearch -regexp $segList2 {^OBR}]

                      does not

                      This section of code later in my script was having the same sorts of issues –

                      extracted area –


                      # Handle 1 (duplicate)

                                     if {$rc == 1} {

                                         set msec [clock click -microseconds]

                                         echo “ORMCONTENT is a duplicate”

                                         set msg       [msgget $mh]                   ;# Get a copy of the message

                                         set segList2  [split $msg r]                ;# split msg by carriage return to get the second segment list

                                         set fieldSep2 [string index $msg 3]          ;# determine field separator should be pipe

                                         set OBR_pos2 [lsearch -regexp $segList2 {^OBR}] ;# just the OBR’s

                                       # set OBR_pos2 [lsearch -all -regexp $segList2 {^OBR}]   ;# OBR break down    

                                         if {$OBR_id2 ne $ORC_id2} {continue}  

                                       

                                       foreach  OBR_idx2 $OBR_pos2 {

                                             set OBR_Seg2  [lindex $segList2 $OBR_idx2]

                                             set segList2 [lreplace $segList2 $OBR_idx2 $OBR_idx2 ]

                                             set newMsg   [join $segList2 r]

                                             msgset $mh $newMsg

                                             if { $OBR_Seg2 != “”} {

                                             echo *new message below

                                             echo “$msg”

                                       

                                             set emailto   nelsol1@mmc.org

                                             set mynote1   “From thread [msgmetaget $mh ORIGSOURCECONN]r”

                                             set mynote2   “[msgmetaget $mh DRIVERCTL]r”

                                             set mynote3   “$module r”

                                             set mynote4   “Message sent to the Error Database:r”

                                             set mynote5   >$msg<                                          ;# was msg before newMsg

                      catch {exec echo $mynote1$mynote2$mynote3$mynote4$mynote5nnRemoved: $OBR_Seg2 nn $ORMCONTENT | mail -s “CONFMSG FULL duplicate segment removed $MSH_id9 $OBR_id2:$OBR_id3:$OBR_id4 $rc” $emailto}

                                                                   

                                                                    }

                                                                     }     ;# end foreach

                                                 } ;# end if rc indicates a duplicate

                      Lawrence Nelson
                      System Architect - MaineHealth IT

                    • #84270
                      Charlie Bursell
                      Participant

                        set OBR_pos2 [lsearch -all -regexp $segList2 {^OBR}]

                        Should return all locations of OBR segments within the list.  If not it is not a proper list

                        Take a look at your lreplace command.  It should be:

                        lreplace list first last ?element element …?

                        I did not take the time to evaluate the whole script.  I will let others chime in for that

                      • #84271
                        Jeff Dinsmore
                        Participant

                          Charlie is certainly right about using lsearch with the -regexp option to search for ORC/OBR only at the beginning of each list element.

                          Max and Charlie are also correct when stating that “eq” and “ne” should be used for string comparisons.  Unexpected things happen if you use “==” and “!=”.  I learned this lesson the hard (and confusing) way.

                          So, to the original question.

                          The basic problem, as Max observed, is that the code is looping through all OBR segments for each ORC segment – thus duplicating results.

                          Max’s solution checks that the ORC and OBR segments match – based on the placer order numbers in ORC-2.2 and OBR-2.2.

                          If those are reliable, that’s probably the most certain way to match ORC to OBR.

                          If they’re not reliable, or if one order number may be listed in multiple ORC or OBR segments, you can find OBR segments by position relative to the a given ORC by removing the OBR foreach and replacing it with processing for the “next” OBR after the current ORC – something like this:

                          Code:

                          set ORCpos [lsearch -all -regexp $segList “^ORC”]             ;# ORC break down

                          foreach ORCidx $ORCpos {
                          set ORCSeg     [lindex $segList $ORCidx]
                          set ORCFlds    [split $ORCSeg $fieldSep]
                          set ORC_id1    [lindex $ORCFlds 1]
                          set ORC_id2    [lindex $ORCFlds 2]
                          set ORC_id3    [lindex $ORCFlds 3]
                          set ORC_idSeg1 [split $ORC_id1 $compSep]
                          set ORC_idSeg2 [split $ORC_id2 $compSep]
                          set ORC_idSeg3 [split $ORC_id3 $compSep]
                          set ORC_id1a    [lindex $ORC_idSeg1 0]
                          set ORC_id2a    [lindex $ORC_idSeg2 0]
                          set ORC_id3a    [lindex $ORC_idSeg3 0]

                          #OBR

                          #
                          # The problem was that the original code was looping through all OBR segments FOREACH ORC segment
                          #    What we really want is to find the NEXT OBR after each ORC
                          #
                          # So, we lsearch for the next OBR starting at the current ORCidx
                          #     position – using the -start option for lsearch
                          #

                          if { [set OBRidx [lsearch -regexp -start $ORCidx $segList “^OBR”]] >= 0 } {

                          # Process only one OBR per ORC

                          set OBRSeg     [lindex $segList $OBRidx]
                          set OBRFlds    [split $OBRSeg $fieldSep]
                          set OBR_id2    [lindex $OBRFlds 2]
                          set OBR_id3    [lindex $OBRFlds 3]
                          set OBR_id4    [lindex $OBRFlds 4]
                          set OBR_idSeg2 [split $OBR_id2 $compSep]
                          set OBR_idSeg3 [split $OBR_id3 $compSep]
                          set OBR_idSeg4 [split $OBR_id4 $compSep]
                          set OBR_id2a    [lindex $OBR_idSeg2 0]
                          set OBR_id3a    [lindex $OBR_idSeg3 0]
                          set OBR_id4a    [lindex $OBR_idSeg4 0]

                          set ORMCONTENT {}
                          set ORMCONTENT  “$ORC_id1a:$ORC_id2a:$ORC_id3a:$OBR_id2a:$OBR_id3a:$OBR_id4a”
                          echo ORMCONTENT = $ORMCONTENT

                          }

                          }  

                          This produces your desired result :

                          Quote:

                          ORMCONTENT = NW:2516511-5::2516511-5::CMPNX

                          ORMCONTENT = NW:2516511-6::2516511-6::CBCD

                          ORMCONTENT = NW:2516511-7::2516511-7::LPPR1

                          ORMCONTENT = NW:2516511-8::2516511-8::TSH

                          Jeff Dinsmore
                          Chesapeake Regional Healthcare

                        • #84272
                          Abe Rastkar
                          Participant

                            Hi,

                            I am assuming that you need to extract the list of OBR segments for each ORC segment in your report.

                            since you are searching the segment list in general, it finds all OBR segments without regard to which ORC they belong to.

                            the search for the OBR segment should be limited to the OBR’s preceding the next ORC. so if you search for the next OBR one at a time (until you get to the next ORC), rather than using the -all parameter, it should give you the list you need.

                          • #84273
                            Lawrence Nelson
                            Participant

                              To Jeff Dinsmore – and all others –

                              I have implemented Max- Charlie then Jeff’s suggestions successfully.

                              Thank you all for your time and input and expertise.

                              Lawrence Nelson
                              System Architect - MaineHealth IT

                            • #84274
                              David Barr
                              Participant

                                Here’s another way to do it:

                                Code:

                                set fieldSep   [string index $msg 3]
                                set compSep    [string index $msg 4]
                                set segList    [split $msg r]

                                foreach seg [lsearch -inline -all -regexp $segList {^(ORC|OBR)}] {
                                   set fieldList [split $seg $fieldSep]
                                   set segName [lindex $fieldList 0]
                                   foreach fieldNum { 1 2 3 4 } {
                                       set field [lindex $fieldList $fieldNum]
                                       set compList [split $field $compSep]
                                       set ${segName}_id${fieldNum}a [lindex $compList 0]
                                   }
                                   if { $segName eq “OBR” } {
                                       set ORMCONTENT “$ORC_id1a:$ORC_id2a:$ORC_id3a:$OBR_id2a:$OBR_id3a:$OBR_id4a”
                                       puts “ORMCONTENT = $ORMCONTENT”
                                   }
                                }

                                The main advantage is you only do one lsearch, and anytime you’re processing an OBR segment you have the values left over from the last ORC that you processed.

                            Viewing 20 reply threads
                            • The forum ‘Tcl Library’ is closed to new topics and replies.