Understanding Arcade Syntax: Expects() and FeatureSetByName()

208
5
03-26-2024 12:08 PM
VinceE
by
Occasional Contributor II

I am trying to write a Calculation style Attribute Rule to restrict entries into a field to be unique values within the field. As an example, more than one row in the given table can't have a value of "TEST" in the given field--entries must be unique.

The below achieves this (might not handle NULLs, but I can sort that out). What is constantly irritating to me is how I cannot figure out how to use the variables defined on the first few lines in the "FeatureSetByName()" and "Expects()" function calls? Updating the FeatureSetByName() call with the fcName and fldName variables will work when I hit "OK" in the AR code editor, but then fail when I try to save the rule. Updating Expects() to use the fldName variable throws an error right in the editor.

Why do these functions work this way? If I change the name of my field, I have to go in and retype it 3 different times in the code? Why can I not just use one single variable for those names? Is this some Arcade/JavaScript idiosyncrasy I just don't understand?

Thanks in advance to anyone who can sort me out on this. The point is to create a rule that can be used in different locations, with minimal updates to only the INPUTS section. Esri's example (link in the code below) hard-codes things, which is silly from a reusability standpoint.

// INPUTS
var fcName = "TEST";
var fldName = "Name_Text";

// These two lines must be written with the actual strings, not the variables above.
var features = FeatureSetByName($datastore, "TEST", ["Name_Text"], false);
Expects($feature, "Name_Text");

// MAIN
// If any values in the field match the current row's value (and the IDs are different),
//    this is a duplicate, and an error.
// Largely copied from:
// https://support.esri.com/en-us/knowledge-base/how-to-identify-a-duplicate-field-value-using-an-attrib-000029088
for (var i in features) {
    if ((i[fldName] == $feature[fldName]) && (i.OBJECTID != $feature.OBJECTID)) {
       return {"errorMessage": "ERROR: value not unique within field!"}
    }
}

// If error above not found, return results dict with value as-is.
var fldUpdates = Dictionary()
fldUpdates[fldName] = $feature[fldName]

Console({"result": {"attributes": fldUpdates}})
return {"result": {"attributes": fldUpdates}}

 

0 Kudos
5 Replies
RPGIS
by
Occasional Contributor III

The issues with this, that I have discovered, is there is a bug that ESRI is aware of where assigning the feature name to a variable will cause some issues.

The FeatureSetByName is used to call an entire feature. With this you have to specify the exact name of the featureclass or table, otherwise it will result in an error when you try to run the code. The other thing is you have to include all fields that you want to check. I noticed that the "OBJECTID" field was missing which would also result in an error. It will check when running the code validation for errors but result in an error when ran.

The Expects can be used on $featureset or $feature, but if used on $feature will only return values within that row/record. You will want to specify a $featureset in order to return all values within the specified table/featureclass.

Give the code below a try and see if it works for you.

 

// INPUTS
var fcName = "TEST"
var fldName = "Name_Text"
var OIDField = 'OBJECTID'
var Testing = $feature.Name_Text

// These two lines must be written with the actual strings, not the variables above.
Expects($featureset, OIDField , fldName )
for (var i in $featureset) {
    if ((i[fldName] == Testing ) && (i[OIDField ] != $feature[OIDField ])) {
       return {"errorMessage": "ERROR: value not unique within field!"}
    }
}
// If error above not found, return results dict with value as-is.
var fldUpdates = { fldName : Testing }
Console({"result": {"attributes": fldUpdates}})
return {"result": {"attributes": fldUpdates}}

 

If that code does not work you can try this one.

 

// INPUTS
var fcName = "TEST"
var Testing = $feature.Name_Text
var OID = $feature.OBJECTID
var OIDField = "OBJECTID"
var NameField = "Name_Text"

// These two lines must be written with the actual strings, not the variables above.
var features = FeatureSetByName($datastore, "TEST", [OIDField , NameField ])
for (var i in features) {
    if ((i[NameField] == Testing ) && (i[OIDField] != OID )) {
       return {"errorMessage": "ERROR: value not unique within field!"}
    }
}

// If error above not found, return results dict with value as-is.
var fldUpdates = { NameField : Testing }
var Result = {"result": {"attributes": fldUpdates}}
Console(Result )
return Result

 

 

VinceE
by
Occasional Contributor II

Thanks for the inputs @RPGIS, but the code I have provided already "works"--even without specifying this line below. Maybe that's because the Arcade "environment" knows that all feature classes/tables will have an ObjectID, so you don't need to specify? Regardless, it seems inconsistent. But I don't have it listed in my version, and things work as expected.

var OID = $feature.OBJECTID

My issue is that I don't want to have to specify the field name three different times in the same code. I'm not saying Python is without problems, but coming from Python there would never be a case where I would have to hard-code a string three different times in the same extremely small block of code. I would assign the string field name to a variable, and then use that variable in every instance where it is needed--if the field name changes, I change the single instance of that variable assignment, and it updates everywhere.

In my example, and both of your examples, we are specifying the same field name "Name_Text" three different times in the same tiny script. If this is a bug, fine, but if this is how the language was designed... why?

0 Kudos
RPGIS
by
Occasional Contributor III

It is still a relatively new language that even I don't know why some things work and others don't. I also code in python and only started using arcade about a year ago, and I still don't understand why some things that work in other programming languages doesn't work in arcade. I also didn't realize that I made a mistake in one of the examples that I provided. You could have the field name variable used within the FeatureSetByName. That I know does work. I will need to update it to show that.

VinceE
by
Occasional Contributor II

Fair enough, I appreciate the insights. I'll go ahead and play around with replacing the string in FeatureSetByName. Thanks again!

0 Kudos
RPGIS
by
Occasional Contributor III

You're welcome.

0 Kudos