Question
Mark OReilly · Jun 23

Global Looping

I haver read $Query and $Order but still not getting the code that i am looking to work correctly. 

I have a global like 

^TestGlobal("Not Configured","Value 1")=""

^TestGlobal("Not Configured","Value 2")=""

I am trying to loop through and get output of all values in csp page by script. 

How in a loop does this work. 

I tried the for loop only getting value 1 not both the values

Set node = $Query(^TestGlobal("NotConfigured"))
   WRITE !,node
  FOR   {
    SET queryary=$QUERY(node)
        QUIT:queryary=""  
        WRITE !,queryary
  }

Product version: IRIS 2022.1
0
0 348
Discussion (12)3
Log in or sign up to continue

You just miss setting node to the found value and the indirection for the node reference
Set node $Query(^TestGlobal("NotConfigured"))
   WRITE !,node
  FOR   {
    SET queryary=$QUERY(@node)
        QUIT:queryary=""  
        WRITE !,queryary
       SET node=queryary

  }
to avoid issues with variable scoping use %node instead of node  for proper work of indirection

Hi Still not working. Might be my misexplaining

Two values from the global veiw page

1:  ^je1("NotConfigured","CBB") = "" 2:  ^je1("NotConfigured","CH11") = "" Total: 2 [End of global]

All i'm getting is the first 

Set node = $Query(^je1("NotConfigured"))
   WRITE !,node
  FOR   {
    SET queryary=$QUERY(node)
        QUIT:queryary=""  
        WRITE !,queryary
        SET node=queryary
  }

In terminal we would have used ^%G then je1("NotConfigured", looking the exact same but in code in objectscript

queryary is blank after the first query so node is blank

$QUERY() needs a Global reference:

  • ^je1("NotConfigured"   is OK
  • node is just a local variable and not OK
  • to use it you have to apply an indirection  >>> @node

I have edited my reply after the first send
and better use %node as indirection is context sensitive.

Yup, that's simpler way to do it instead of $Q. It's same as this: s sub="" F  s sub=$O(^je1("NotConfigured",sub)) Q:=sub=""  w sub,!  just without redirection. The main key here if you are looking for just sub script level then $O is what you need. If you want whole global ref, then aka instead of getting just CBB or CH11 you would get ^je1("NotConfigured","CBB"). In your case this would exit the loop since your loop is looking at $Q(@node) where node = ^je1("NotConfigured","CBB") instead of ^je1("NotConfigured") and since there is no sub script at that level your loop quits (hence only why you get the first level from your initial Set command). So your code should look like this for $Q to work:

Set node = "^je1(""NotConfigured"")"
   WRITE !,node
  FOR   {
    SET node=$QUERY(@node)
        QUIT:node=""  
        WRITE !, node
  }

$Q is useful when you want to check what level exist under a global which may be defined dynamically or something close to that, but $O does the job for everything else. 

You need to understand the difference between $order and $query; they both handle globals/arrays differently for different purposes.
$order is the more straightforward to use (and more commonly used); it scans down a particular node of a global/array. For example for your example:

`set n=""

for{

set n=$order(^TestGlobal("Not Configured",n))

quit:n=""

; do something with n

} `

$query is more useful if the global structure is unknown or less structured. It starts at the top of the global and returns the entire subscript string at a given level. So again for your example, the first $query would return ("Not Configured","Value 1"). You could then use $QL to get the number of subscripts at that level (2 in this case), and $qs(subscripts,position) to get the value of the subscript.

set gbl="TestGlobal"
set node=$q(@gbl@(""))
w node ; this would return TestGlobal("Not Configured","Value 1")
w $ql(node) ; this would return 2
w $qs(node,1) ; this would return "not configured"
w $qs(node,2) ; this would return "Value 1"
w @node ; returns the data at that node; in this example null

$order is the more commonly used.

You need to understand how to use globals and arrays to efficiently store data, and how to traverse them using $order. Globals and arrays are handled the same except globals are store on disk (persistant/permanent) and arrays are stored in memory (volatile/temporary).

Hope this helps.

many thanks, for teaching this lesson on basics. 

Although the above description says $ORDER scans "down" a multidimensional global, other programers might say it scans "sideways".  There are many different structures for databases.  E.g., there are network databases (sometimes called CODASYL databases); there are hierarchical databases (like ObjectScript multidimensional arrays/globals); there are relational databases (often accessed by the SQL language); ...

ObjectScript is based on the ANSI M language standard.  I believe that the name of the ANSI M hierarchical function $QUERY has always been $QUERY but the original name of the ANSI M hierarchical function $ORDER was formerly $NEXT.  $NEXT is very similar to $ORDER but $NEXT had problems with its starting/ending subscript values.  IRIS ObjectScript no longer documents the obsolete $NEXT function but the ObjectScript compiler still accepts programs using $NEXT for backwards compatibility.

Consider the following ObjectScript global array:

USER>ZWRITE ^g
^g("a")="a"
^g("a",1)="a1"
^g("b",1)="b1"
^g("b",1,"c")="b1c"
^g("c")="c"
^g("c","b10")="cb10"
^g("c","b2")="cb2"
^g("d",2)="d2"
^g("d",10)="d10"

Consider the following walk sideways by $ORDER along the first subscript of ^g"

USER>set s=""
USER>for { SET s=$ORDER(^g(s))  QUIT:s=""  WRITE $NAME(^g(s)),! }    
^g("a")
^g("b")
^g("c")
^g("d")

Although these 4 globals contain values below them, the $ORDER walks did not walk down to deeper subscripts.  As it walked sideways, it returned the subscripts "b" and "d" even though ^g("b") and ^g("d") did not have values of their own but only values underneath them.

Now consider the walk down deeper by $QUERY through all the subscripts of ^g(...) at all subscript levels:

USER>set s="^g"
USER>for { WRITE s,!  SET s=$QUERY(@s)  QUIT:s="" }               
^g
^g("a")
^g("a",1)
^g("b",1)
^g("b",1,"c")
^g("c")
^g("c","b10")
^g("c","b2")
^g("d",2)
^g("d",10)

This walk by $QUERY was told to start at ^g and every call on $QUERY went through every subscripted node of ^g(...) that contained a value regardless of the number of subscripts needed.  However, elements ^g("b") and ^g("d") that did not contain values of their own were skipped by the $QUERY walk as it continued on to nodes with deeper subscripts that did contain values.

Also note that each $ORDER evaluation returned only a single subscript value as it walked sideways while each $QUERY evaluation returned a string containing the variable name along with all the subscript values of that particular multidimensional array node.

Actually I was always using $Zorder ($ZO) which was "invented" 30 years ago, before $Query (popular MSM, DSM etc.)
Another thing is that $Order is a "vertical" way of looping through an array/global/PVC and $Query (or $ZO) are meant to loop in a "horizontal" way (same as you ZWRITE it)

it has the same functionality, and very easy to use:
Set node = "^TestGlobal(""Not Configured"")" W !,node
^TestGlobal("Not Configured")
F  S node=$ZO(@node) Q:node=""  w !,node,"=",@node
^TestGlobal("Not Configured","Value 1")=value 1
^TestGlobal("Not Configured","Value 2")=value 2

Hi @Yaron Munz 
In 1978 when DSM-11 was first released there was no $QUERY() but $NEXT(). doing the job.
Could have been in MUMPS.4B as well.(?)

$ORDER() is the contemporary equivalent to $NEXT().  $ZORDER() would have been the equivalent to $QUERY() but I'm not sure if it existed in 1978, I think it may have been introduced a little later in DSM-11.