Request for assistance with a FOREACH problem.

Homepage 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.

Forum Statistics

Registered Users
5,074
Forums
28
Topics
9,252
Replies
34,241
Topic Tags
275