ArcGIS Pro: Advanced Attribute Appending

3714
15
Jump to solution
01-31-2020 12:17 PM
by Anonymous User
Not applicable

Attempting to append existing field values from and existing feature class to empty field values in features on creation for an array of various related feature classes.

To be more specific I have many traffic assets that all relate back to a Cabinet, so every time a feature that is related to the Cabinet (ie. signal head, handhole, signal pole ect.) I want to append the Cabinet_ID and other field values.

the goal is for this to perform edit users who are collecting field points or users that are digitizing over aerials. 

 

My initial trail with attempting to mimic the filed mapping with ARCADE and Attribute Rules is described below.

 

I know that the return expression would involve this snippet if replicating the Field Mapper return expression

-------------------------------------------------------------------------------------

return {
"idCabinet" : $sourceFeature['idCabinet']
}

--------------------------------------------------------------------------------------

I am trying to work with a different script that generates by intersect the source field value to the target field; it is also part of an Attribute Rule

-----------------------------------------------------------------------------------------------------------------------------------------------------------

var fsMACOG_Intersections_Poly = FeatureSetByName($datastore, "MACOG_Intersections_Poly", ["MACOG_ID"])
var fsMACOG_Intersections_PolyIntersect = Intersects(fsMACOG_Intersections_Poly, $feature)
var MACOG_Intersections_Poly = First(fsMACOG_Intersections_PolyIntersect)

if (MACOG_Intersections_Poly == null) return {"errorMessage": "MACOG_ID not found"}

return MACOG_Intersections_Poly.MACOG_ID

-----------------------------------------------------------------------------------------------------------------------------------------------------------

tinkering around with the ARCADE Sandbox, the script currently looks like this

-----------------------------------------------------------------------------------------------------------------------------------------------------------

var fsPrg_SignalInvent_Cabinet = FeatureSetByName($sourcefeature, "Prg_SignalInvent_HandHoles", ["idCabinet"])

var fsPrg_SignalInvent_HandHoles = FeatureSetByName($targetfeature, "Prg_SignalInvent_HandHoles", ["idCabinet"])

if(isempty($targetfeature.idCabinet))

return {
"idCabinet" : $sourceFeature['idCabinet']
}

else return {}

0 Kudos
1 Solution

Accepted Solutions
RobertKrisher
Esri Regular Contributor

Wait...was this whole thread about wanting to create one point/line feature with a bunch of features with a predefined set of attributes?  Oh man, if that's the case I'd 1000% recommend using feature template with related tables (for a point/line with related objects) or for a predefined set of related features i'd use the preset template.

View solution in original post

15 Replies
RobertKrisher
Esri Regular Contributor

My first thought was that you could create an attribute rule that would fire on creation of a feature to automatically inherit the attribute (and relate) the new feature to the traffic cabinet.  If you needed something more robust you could always create one or more batch calculate (or validation) rules that could populate or ensure these values are consistent.

by Anonymous User
Not applicable

Robert,

Researching I have come across some examples where I can create a rule that automatically inherits the attributes, but when I look through arcade and attribute rules I am having trouble figuring out relating / utilizing relationship classes, besides Add Rule To Relationship class. Is there a function for relationships or would a more technical script need to be made using ARCADE?

0 Kudos
RobertKrisher
Esri Regular Contributor

Brian,

  There is an arcade function that lets you get all of the features related to the current feature ( Data Functions | ArcGIS for Developers  ).  Is this what you're looking for?

XanderBakker
Esri Esteemed Contributor

Hi Brian Acheff ,

If you are using the Configure field mapping—ArcGIS Pro | Documentation tool you have access to the "$sourcefeature" and "$targetfeature". I don't think these are available when creating an attribute rule though.

CC. mmiller-esristaff 

by Anonymous User
Not applicable

Xander,

I have looked into that method and would work great for post collection and editing, but I am looking for something that can be utilized in the field or during collection. I do have use for field mapping in another project though, it would be really cool to see if the "$sourcefeature" and "$targetfeature" globals could be used with attribute rules. 

--------------------------------------------------------------------------------------------------------------------------------------------------------

Robert & Xander

Yes that is what I am looking for. I used the following script to test:

var MACOG_Intersections_Poly = FeatureSetByRelationshipName($feature, 'MACOG_Intersections_Poly_HAS_Prg_SignalInvent_HandHoles', ['MACOG_ID'], false)
Return 'MACOG_ID'‍‍‍‍‍‍‍‍‍‍

this rule and the others I am using work great for generating unique_IDs  / inheriting values from related features. The next question I have is about updating these fields. I know that attribute rules gives you the option to fire on Update and that with ArcGIS Pro 2.5 the $originalFeature global has been added to clean up the unwanted occurrences that are triggered when editing / attribute rules fire on Update.

Below I pasted attribute rules scripts that use the Attribute Rules dictionary keywords. Compared to creating many relationship classes and using the FeatureSetByRelationshipName function, what would be a benefit of use scripting that utilizes Attribute Rules dictionary keywords?

return { 'result': noAddress + ' addresses found in the district.', 'edit': [{ 'className': 'Address_pnts', 'updates': AddList }]

____________________________________________________________________________________________________

https://pro.arcgis.com/en/pro-app/help/data/geodatabases/overview/attribute-rule-script-expression.h... 

Mark other features requiring evaluation

You can author a calculation rule that marks other features as requiring either calculation or validation. When performing a calculation, the calculationRequired or validationRequired keyword can be used in a dictionary to reset the Validation Status attribute for one or more features. This is useful when a feature class is dependent on another feature class. In this example, the AssetID field in the Transformer feature class depends on the intersecting Substation feature class. A calculation rule is created on the yearName field of the Substation feature class. When the substation name is updated, the new name and the current year are stored in the yearName field. As part of this logic, all the transformers intersecting the substation in the Transformer feature class are marked as requiring calculation. There is a batch calculation rule on the Transformer class that will calculate the Transformer AssetID the next time the rule is evaluated to reflect the new name and year of the substation.

//Updating the substation name marks its transformers as requiring calculation and updates the yearName to the new name and year. //To recalculate the facility id on all transformers, mark all associated transformers as requiring calculation.var fsDevice =  FeatureSetByName($datastore, "Transformer", ["globalid"], false)var fsDeviceIntersects = Intersects (fsDevice, Geometry($feature)) var transformers = [];var count = 0; for (var i in fsDeviceIntersects)    transformers[count++] = i.globalid;var newName = $feature.name + " " + Year(Now())return {    'result': newName,     'calculationRequired':         [           {               'className':"Transformer",               'globalIDs': transformers            }        ]    }

Edit another feature class

You can use attribute rules to perform inserts, updates, and deletes to another feature class by using the edit dictionary keyword. The example below is a calculation rule on a text field of a district boundaries feature class. When editing a polygon in the district boundaries feature class, this attribute rule will update any intersecting address points with the district name.

var fsAddress = FeatureSetByName($datastore, "Address_pnts", ["globalid"], true)var fsListAddpnts = Intersects(fsAddress, $feature)var AddList = []var counter = 0var noAddress = Count(fsListAddpnts)if (noAddress > 0) {     for (var address in fsListAddpnts) {         AddList[counter] = {             'globalid': address.globalid,             'attributes': {                 'add_district_name': $feature.DistrictName             }         }         counter++     }     return {         'result': noAddress + ' addresses found in the district.',         'edit': [{             'className': 'Address_pnts',             'updates': AddList         }]     } } else {     return 'No address points in district.'}

___________________________________________________________________

Advanced Attribute Rules – Editing features on another class with attribute rules 

Immediate Attribute Rule

Exclude from application evaluation has to be turned on for any attribute rule that returns dictionary

Creating features with attribute rules

Creating features with attribute rules

Note: The `result` key is used to return the value to persist in the field `Field` which the attribute rule is assigned to. In this case I really didn't do anything to the feature being created so I just returned the same value of the field `Field` (I know, terrible name for a field sorry). When returning the same value, the system will detect that there is no change and will not perform an additional edit to the feature. This is useful to avoid triggering behavior associated with the field (if any) such as extension specific behavior, e.g. dirty area management in utility network.

 

Update existing features in another class

Now we want to add another attribute rule that performs an update. With this rule we want to ensure that the buffered polygon moves along with the point feature when it is moved.  The best solution to achieve this would be to update the buffered polygon feature geometry with a new buffer after the update.

 

0 Kudos
by Anonymous User
Not applicable

Though the FeatureSetByRelationshipName function works, it returns the field name and not the values that is populated from the nextsequence value function that populates the asset_id value of the feature from which the record is being fetched.

I now see where using the dictionary keywords would come into play, if the FeatureSetByRelationshipName cannot return field values, just field names.

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Brian Acheff ,

You mentioned this comment:

I now see where using the dictionary keywords would come into play, if the FeatureSetByRelationshipName cannot return field values, just field names.

I guess the comment refers to this snippet:

var MACOG_Intersections_Poly = FeatureSetByRelationshipName($feature, 'MACOG_Intersections_Poly_HAS_Prg_SignalInvent_HandHoles', ['MACOG_ID'], false)
Return 'MACOG_ID'

In that snippet you could have scratched the first line and obtained the same since you are not doing anything with the featureset you return by FeatureSetByRelationshipName.

Have a look at this expression:

var first_related_record = First(FeatureSetByRelationshipName($feature, 'MACOG_Intersections_Poly_HAS_Prg_SignalInvent_HandHoles', ['MACOG_ID'], false));
Return first_related_record["MACOG_ID"];

... it retrieves the First record and from that record queries the field "MACOG_ID". This will return the field value (if it finds a related records and that field exists).

by Anonymous User
Not applicable

 Xander Bakker

When I test the expression you provided and was provided with the error message that the "Type" does not support the function "first". After researching some resources, I now know that when using the "first" function the type must be either "Array" or "FeatureSet"

Attempted to use dictionary keywords with this script, the expression is valid, but returns nothing, but when I attempt to creat a new feature and evaluation error is given. I guess I am confused on how if I have a relationship class where Hand Holes are related to Cabinets, and the inheriting of the idCabinet value to the Hand Hole feature class is dependent upon there being a relationship between the features that occurs on creation of a handhole. To my knowledge I have to manually select the features to be added to the relationship to populate the idCabinet_GUID field. Hopefully this makes some kind of sense?

var first_related_record = (FeatureSetByRelationshipName($feature, 'Prg_SignalInvent_Cabinet_HAS_Prg_SignalInvent_HandHoles', ['idCabinet'], false));
Return { "result": $feature.idCabinet,
      //this keyword indicates an edit that need to happen, its an array since we can make many edits
       "edit": [
           {  
              //the other class we want to edit
               "className" : "prg_SignalInvent_HandHoles",
               //the type of edit, in this case we want to update so we say `updates`, its an array since we can make many updates
               "adds" : [
                      { 
                            //what feature we need to update? we can either find it by the globalid or the objectId
                            "attributes":
                            {
                            "idCabinet" : $feature.idCabinet,
                          }

                     }

             ]
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Also came across post on GeoNet where the user is trying to do a similar task of fetching a field value from a table and appending it to a target feature, I input some of my features. to test, but am given an error at line 27 for an expected identifier. How do you reference another field from a related table in Arcade? 

//call out Cabinet feature class idCabinet
var id = $feature.idCabinet
//access Hand Hole feature class table
var tbl = FeatureSetByRelationshipName($feature, 'prg_SignalInvent_HandHoles', 'idCabinet', true);
var sql = "idCabinet = '" + ID + "'";
//filter Hand Hole table using sql expression
var related_data = Filter(tbl, sql);
//count the resulting records
var cnt = Count(related_data);

//initaiate a variable to hold the result
var result = cnt + "related records";

//check if there are related records found for the current ID
if (cnt > 0) {
//loop through related data){
for (var row in related_data) {
// read some data and create the line you want
var line = TextFormatting.NewLine + " - " + row.SomeFieldOfInterest;
//add the line to the result
result += line;
}
} else {
result = "No related records:";
}
//return result
return result;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Brian Acheff ,

The error message is indicating the there is something wrong with the expression and the FeatureSetByRelationshipName is not returning a FeatureSet as it is supposed to do (perhaps a mistake in the spelling of the name). First can be applied to arrays and FeatureSets so that is not the problem.

You could try and test this and see what it returns:

var test = Type(FeatureSetByRelationshipName($feature, 'MACOG_Intersections_Poly_HAS_Prg_SignalInvent_HandHoles', ['MACOG_ID'], false));
Return test;

0 Kudos