You'll use both %Library.DynamicObject and %Library.DynamicArray classes for this. When you do JSON.%Get("Practice") the resulting object is a dynamic array, not a dynamic object, so it works a little differently. Then when you get the first element of the array, you have another dynamic object. Try:

//Get the array Practice
set array = JSON.%Get("Practice")
//Get item 0 from the array we just got
set nodejson = array.%Get(0)
//Get the value of Node
set node = nodejson.%Get("Node")
//Write the value out (or do whatever else you need)
write node

If you use a dataCombo, the first column of the SQL query is the actual value of the dataCombo and the second column is the display value. So if you defined a dataCombo with sql="select Analyst, Analyst->Name from Analysts" (or whatever your table is) you'll get what you want.

In that case, you'll also want to define the sqlLookup property of the dataCombo. That tells the Zen page how to find the correct display value when the value of the control is changed programatically, so something like "select Analyst->Name from Analysts where Analyst=?"

Yes, you can do that, but I have another recommendation.

You generally want to be careful with what you do in %SYS, and you might not want a user to have permission to access that stuff all the time. You could create a new security role that gives the right permissions to access whatever you're accessing, then assign it in that method, run the code that needs it, and remove it. So let's say your new security role is called MyRole:

set $ROLES = MyRole
set oldns = $NAMESPACE
new $NAMESPACE
set $NAMESPACE = "%SYS"
// Do your stuff here.
new $NAMESPACE
set $NAMESPACE = oldns
new $ROLES

The $ROLES special variable is used to manage roles that are added and removed programatically during the execution of code, but does not affect roles assigned to the user in the management portal.

No, it doesn't run as soon as the previous task ends. It runs at the next scheduled time. So in my example above, if your task runs at 12:00:00 and doesn't finish until 12:01:30, the next scheduled time is 12:02:00, so that's when it'll run next. I'm not sure how far back in versions this goes, but you might be able to change that behavior so it's more like what you're expecting.

There isn't a consistent mapping for everything, but if you're in the %SYS namespace, you can query the tables %SYS.Task and %SYS_Task.History to find these specific things. Some of the security related things are in the Security scheme, like Security.Roles and Security.Users.

When you're in the SQL part of the system management portal, if you check the box to show system tables on the left, you can see a lot of these then under tables, and you'll be able to guess what a lot of them are just based on the names.

If you want to treat them as lists, you probably want to use $LISTFROMSTRING along with $LISTGET, $LISTFIND, and $LISTLENGTH. All of which can be abbreviated to their initials, by the way - $LFS, $LG, $LF, $LL.

set y = $LFS("Red,Green,Orange,Yellow")
set x = $LFS("Purple,Black,Yellow,Pink")
for i=1:1:$LL(x){
    if $LF(y,$LG(x,i)) > 0 { 
        write $LG(x,i)_" found in both lists!",!
        //Or whatever else you want to do when you find a match here . . .
    }
}

Yes, you do have to tread lightly and program very carefully if you mess with those. Errors in them could make it impossible to start or log into IRIS. This is straight from the documentation about those routines:

Make sure that the routines are well-behaved under all possible conditions. They should be written defensively. That is, they should check to make sure that all the resources needed to complete their task are at hand and, if possible, reserved to them before computation starts. Errors which occur are reported as failures of that system function so it is important to think about the design from the viewpoint of error containment and handling. Failure to properly account for recovery in the face of missing resources or the presence of errors has varied consequences: InterSystems IRIS may fail to start; major functions such as Studio may act strangely; or more subtle and insidious consequences may occur which are not immediately detected. It is strongly recommended that these routines be carefully written and debugged under simulated conditions, and then tested under simulated environment conditions before being put into production systems.

It doesn't sound like you're trying to do anything too crazy, but do make sure you trap or catch any potential errors anyway.

When using $EXTRACT, you use a * to signify an offset from the end of a string. So if you did $EXTRACT(Str,1,*-1) you would have the string with the last character removed.

Also note that the arguments for the $EXTRACT are the string, the starting character, and the ending character, so in the examples you gave, you're actually telling it to extract from Str starting at Length(Str)-1. You need to have a 1 in there as the second argument to go from the beginning to that character.

You can also use the $ROLES special variable to do that. It contains both the user's assigned roles and any roles you've added during the process. You can't change the user roles, but if you set it that will add a role. So you could do:

set $ROLES = "%All"

Or whatever role you need to add, then do the stuff that requires that roles, then do:

set $ROLES = ""

That will take away the %All role you added, reverting the process to just the user's normal roles.

Phil, I'm not sure about VS Code, but you can do this in studio by creating a new CSP page with the following contents:

<csp:StudioSimpleTemplate name="CustomCommentHead" type="CLS" mode="new">
/// Organization:
/// Version 1.0
/// Author/Co-author:
/// Project: 
/// Date: 
/// Description: 
/// Change Log:
/// Notes:

Then save and compile that file. It doesn't matter where. Then when you click File, New, Custom, you'll see your CustomCommentHead template. If you choose it, you'll get a .cls file with those lines already inserted.

If you're developing in Studio, open the file that contains that TestAccountSearchWithoutAccount method, then click the "View Other Code" button so you're looking at the INT code. If it says no other code to view, that's fine; you're already where you need to be. There should be a small text field near the top of the window with a drop down arrow on its left end. In that text field, type TestAccountSearchWithoutAccount+6 and press enter. That should take you directly to the line where the error is occurring.

Something on that line is trying to reference an object that doesn't exist. That's what "INVALID OREF" means. Whatever objects are on that line, check how they were created and/or opened and see if there's a chance that the object doesn't exist.

After using your %ExecDirect() method, you should have a %SQL.StatementResult Object. Let's assume you called this object rs (for result set). So you did something like set rs = ##class(%SQL.Statement).%ExecDirect(blahblahblah). From there:

//Get the list of columns
set cols = rs.%GetMetaData().columns
//Loop through the result object
while rs.%Next(){
//Loop through the columns
     for x=1:1:rs.%ResultColumnCount{
     //Get the value of each column
         set colValue = rs.%GetData(x)
         //Get the name of each column
         set colName = cols.GetAt(x).colName
         //TODO: Add whatever you're doing with the name and value here
     }
}