That is absolutely possible.
There are two ways to exchange values between (spatially) related tables:
- Pull: When you add or edit a feature, the rule pulls values from features in related tables and stores them in this feature
- Push: When you add or edit a feature, the rule pushes values from this feature to features in related tables
Which method you implement depends on your use case. Some examples (not tested, there might be some missing parentheses and such):
Examples for Pulling:
Featureclass "Assets" and related table "Inspections". New Inspection should use the Asset's "Value1" attribute.
// Calculation Attribute Rule on Inspections
// Field: Value1
// Triggers: Insert
// get the related asset
var asset_id = $feature.AssetID
var assets = FeaturesetByName($datastore, "Assets")
var asset = First(Filter(assets, "AssetID = @asset_id"))
// if there is no related asset, abort
if(asset == null) { return }
// else return the asset's Value1 attribute
return asset.Value1
Same as above, but the new Inspection should use the Asset's "Value1" and "Value2" attributes.
// Calculation Attribute Rule on Inspections
// Field: leave empty
// Triggers: Insert
// get the related asset
var asset_id = $feature.AssetID
var assets = FeaturesetByName($datastore, "Assets")
var asset = First(Filter(assets, "AssetID = @asset_id"))
// if there is no related asset, abort
if(asset == null) { return }
// else return the asset's Value1 and Value2 attributes
return {
result: {
attributes: {
Value1: asset.Value1,
Value2: asset.Value2
}
}
}
Polygon featureclass "Parks" and point featureclass "Benches". They are related spatially, but Benches should also store the Park's name.
// Calculation Attribute Rule on Benches
// Field: ParkName
// Triggers: Insert
// get the park
var parks = FeaturesetByName($datastore, "Parks")
var park = First(Intersects($feature, parks))
// if there is no intersected park, abort
if(park == null) { return }
// else return the park's name
return park.Name
Examples for Pushing:
Probably the most common one: Featureclass "Assets" and related table "Inspections". When a new Inspection is added, the date of that latest inspection should be stored in the Asset.
// Calculation Attribute Rule on Inspections
// field: leave empty
// Triggers: Insert
// Exclude from application evaluation!
// get the related asset
var asset_id = $feature.AssetID
var assets = FeaturesetByName($datastore, "Assets")
var asset = First(Filter(assets, "AssetID = @asset_id"))
// if there is no related asset, abort
if(asset == null) { return }
// else push an edit to that asset
return {
edit: [{
className: "Assets",
updates: [{
objectID: asset.OBJECTID,
attributes: {
LastInspectionDate: $feature.InspectionDate
}
}]
}]
}
Polygon featureclass "Parks" and point featureclass "Benches". They are related spatially, but Benches also store the Park's name (see examples for pulling). Point featureclass "Trees" also stores the Park's name. If the park is renamed, the new name should be pushed to Benches and Trees.
// Calculation Attribute Rule on Parks
// field: leave empty
// Triggers: Update
// Exclude from application evaluation!
// get the benches
var benches = FeaturesetByName($datastore, "Benches")
var benches_in_park = Intersects($feature, benches)
// create an empty array that will store the update info
var bench_updates = []
// loop over the intersected benches and fill the update array
for(var bench in benches_in_park) {
var update = {
objectID: bench.OBJECTID,
attributes: {ParkName: $feature.Name}
}
Push(bench_updates, update)
}
// do the same for trees
var trees = FeaturesetByName($datastore, "Trees")
var trees_in_park = Intersects($feature, trees)
var tree_updates = []
for(var tree in trees_in_park) {
var update = {
objectID: tree.OBJECTID,
attributes: {ParkName: $feature.Name}
}
Push(tree_updates, update)
}
// push the edits to the other featureclasses
return {
edit: [{
className: "Benches",
updates: bench_updates
},
{
className: "Trees",
updates: tree_updates
}]
}
Point fc and polygon fc. The polygon fc is just a buffer around the point, they are related by PointID. If you add/move/delete a point, the buffer should automatically be created/moved/deleted.
// Calculation Attribute Rule on Points
// field: leave empty
// Triggers: Insert, Update, Delete
// Exclude from application evaluation!
// abort if PointID is null
if($feature.PointID == null) { return }
// create empty arrays to store the edits to the polygon fc
var adds = []
var updates = []
var deletes = []
// get the edit type
var mode = $editcontext.editType
// create the new geometry for the polygon
var default_distance = 10
var buffer_distance = DefaultValue($feature.BufferDistance, default_distance)
var new_geometry = Buffer($feature, buffer_distance)
// get the related polygon
var polygons = FeaturesetByName($datastore, "Polygons")
var point_id = $feature.PointID
var poly = First(Filter(polygons, "PointID = @point_id"))
// if no polygon was found (we're inserting a new point or updating a point with missing buffer), create a new polygon
if(poly == null) {
var new_poly = {
geometry: new_geometry,
attributes: {PointID: $feature.PointID}
}
Push(adds, new_poly)
}
// if a polygon exists
else {
// update? -> set new geometry
if(mode == "UPDATE") {
var updated_poly = {
objectID: poly.OBJECTID,
geometry: new_geometry
}
Push(updates, updated_poly)
}
// delete? -> delete the buffer polygon
if(mode == "DELETE") {
var deleted_poly = {objectID: poly.OBJECTID}
Push(deletes, deleted_poly)
}
}
// Push the edits to the polygon fc
return {
edit: [{
className: "Polygons",
adds: adds,
updates: updates,
deletes: deletes,
}]
}
Push and Pull combined
"Assets" and "Inspections"
// Calculation Attribute Rule on Inspections
// field: leave empty
// Triggers: Insert
// Exclude from application evaluation!
// get the related asset
var asset_id = $feature.AssetID
var assets = FeaturesetByName($datastore, "Assets")
var asset = First(Filter(assets, "AssetID = @asset_id"))
// if there is no related asset, abort
if(asset == null) { return }
// else push an edit to that asset
return {
result: {
attributes: {
Value1: asset.Value1,
Value2: asset.Value2
}
},
edit: [{
className: "Assets",
updates: [{
objectID: asset.OBJECTID,
attributes: {
LastInspectionDate: $feature.InspectionDate
}
}]
}]
}
For more reading:
https://pro.arcgis.com/en/pro-app/latest/help/data/geodatabases/overview/attribute-rule-dictionary-k...
https://www.esri.com/arcgis-blog/products/arcgis-pro/data-management/advanced-gdb-attribute-rules-ed...
Have a great day!
Johannes