Skip to main content

Finding Nodes in a Global Array

Finding Nodes in a Global Array

The Native SDK provides ways to iterate over part or all of a global array. The following topics describe the various iteration methods:

Iterating Over a Set of Child Nodes

Child nodes are sets of subnodes immediately under the same parent node. Any child of the current target node can be addressed by adding only one subscript to the target address. All child nodes under the same parent are sibling nodes of each other. For example, the following global array has six sibling nodes under parent node ^myNames("people"):

  ^myNames                               (valueless root node)
     ^myNames("people")                  (valueless level 1 node)
        ^myNames("people","Anna") = 2    (first level 2 child node)
        ^myNames("people","Julia") = 4
        ^myNames("people","Misha") = 5
        ^myNames("people","Ruri") = 3
        ^myNames("people","Vlad") = 1
        ^myNames("people","Zorro") = -1  (this node will be deleted in example)

Note:
Collation Order

The iterator returns nodes in collation order (alphabetical order in this case: Anna, Julia, Misha, Ruri, Vlad, Zorro). This is not a function of the iterator. When a node is created, InterSystems IRIS automatically stores it in the collation order specified by the storage definition. The nodes in this example would be stored in the order shown, regardless of the order in which they were created.

This section demonstrates the following methods:

  • Methods used to create an iterator and traverse a set of child nodes

    • jdbc.IRIS.getIRISIterator() returns an instance of IRISIterator for the global starting at the specified node.

    • IRISIterator.next() returns the subscript for the next sibling node in collation order.

    • IRISIterator.hasNext() returns true if there is another sibling node in collation order.

  • Methods that act on the current node

    • IRISIterator.getValue() returns the current node value.

    • IRISIterator.getSubscriptValue() returns the current subscript (same value as the last successful call to next()).

    • IRISIterator.remove() deletes the current node and all of its subnodes.

The following example iterates over each child node under ^myNames("people"). It prints the subscript and node value if the value is 0 or more, or deletes the node if the value is negative:

Finding all sibling nodes under ^myNames("people")
// Read child nodes in collation order while iter.hasNext() is true
  System.out.print("Iterate from first node:");
  try {
    IRISIterator iter = irisjv.getIRISIterator("myNames","people");
    while (iter.hasNext()) {
      iter.next();
      if ((Long)iter.getValue()>=0) {
        System.out.print(" \"" + iter.getSubscriptValue() + "\"=" + iter.getValue()); }
      else {
        iter.remove();
      }
    };
  } catch  (Exception e) {
    System.out.println( e.getMessage());
  }

  • The call to getIRISIterator() creates iterator instance iter for the immediate children of ^myNames("people").

  • Each iteration of the while loop performs the following actions:

    • next() determines the subscript of the next valid node in collation order and positions the iterator at that node. (In the first iteration, the subscript is "Anna" and the node value is 2).

    • If the node value returned by getValue() is negative, remove() is called to delete the node (including any subnodes. This is equivalent to calling kill() on the current node).

      Otherwise, getSubscriptValue() and getValue() are used to print the subscript and value of the current node.

  • The while loop is terminated when hasNext() returns false, indicating that there are no more child nodes in this sequence.

This code prints the following line (element "Zorro" was not printed because its value was negative):

  Iterate from first node: "Anna"=2 "Julia"=4 "Misha"=5 "Ruri"=3 "Vlad"=1

This example is extremely simple, and would fail in several situations. What if we don’t want to start with the first or last node? What if the code attempts to get a value from a valueless node? What if the global array has data on more than one level? The following sections describe how to deal with these situations.

Finding Subnodes on All Levels

The next example will search a slightly more complex set of subnodes. We’ll add new child node "dogs" to ^myNames and use it as the target node for this example:

  ^myNames                                         (valueless root node)
     ^myNames("dogs")                              (valueless level 1 node)
        ^myNames("dogs","Balto") = 6
        ^myNames("dogs","Hachiko") = 8
        ^myNames("dogs","Lassie")                  (valueless level 2 node)
           ^myNames("dogs","Lassie","Timmy") = 10  (level 3 node)
        ^myNames("dogs","Whitefang") = 7
     ^myNames("people")                            (valueless level 1 node)
        [five child nodes]                         (as listed in previous example)

Target node ^myNames("dogs") has five subnodes, but only four of them are child nodes. In addition to the four level 2 subnodes, there is also a level 3 subnode, ^myNames("dogs","Lassie","Timmy"). The search will not find "Timmy" because this subnode is the child of "Lassie" (not "dogs"), and therefore is not a sibling of the others.

Note:
Subscript Lists and Node Levels

The term node level refers to the number of subscripts in the subscript list. For example, ^myGlobal("a","b","c") is a “level 3 node,” which is just another way of saying “a node with three subscripts.”

Although node ^myNames("dogs","Lassie") has a child node, it does not have a value. A call to getValue() will return null in this case. The following example searches for children of ^myNames("dogs") in reverse collation order:

Get nodes in reverse order from last node under ^myNames("dogs")
// Read child nodes in descending order while iter.next() is true
  System.out.print("Descend from last node:");
  try {
    IRISIterator iter = irisjv.getIRISIterator("myNames","dogs");
    while (iter.hasPrevious()) {
      iter.previous();
      System.out.print(" \"" + iter.getSubscriptValue() + "\"");
      if (iter.getValue()!=null) System.out.print("=" + iter.getValue());
    };
  } catch  (Exception e) {
    System.out.println( e.getMessage());
  }

This code prints the following line:

Descend from last node: "Whitefang"=7 "Lassie" "Hachiko"=8 "Balto"=6

In the previous example, the search misses several of the nodes in global array ^myNames because the scope of the search is restricted in various ways:

  • Node ^myNames("dogs","Lassie","Timmy") is not found because it is not a level 2 subnode of ^myNames("dogs").

  • Level 2 nodes under ^myNames("people") are not found because they are not siblings of the level 2 nodes under ^myNames("dogs").

The problem in both cases is that previous() and next() only find nodes that are under the same parent and on the same level as the starting address. You must specify a different starting address for each group of sibling nodes.

In most cases, you will probably be processing a known structure, and will traverse the various levels with simple nested calls. In the less common case where a structure has an arbitrary number of levels, the following jdbc.IRIS method can be used to determine if a given node has subnodes:

  • isDefined() — returns 0 if the specified node does not exist, 1 if the node exists and has a value. 10 if the node is valueless but has subnodes, or 11 if it has both a value and subnodes.

If isDefined() returns 10 or 11, subnodes exist and can be processed by creating an iterator as described in the previous examples. A recursive algorithm could use this test to process any number of levels.

FeedbackOpens in a new tab