Select to view content in your preferred language

Update field in Parent layer IF related layer record is given specific field value

811
12
Jump to solution
03-16-2025 09:56 PM
JamesBooth
Regular Contributor

I'm struggling to get this attribute rule working.

My Setup:
Parent Layer: WNV_StagnantWaterSites (point feature class)
Related Layer: WNV_SiteVisits (point feature class)
Relationship: 1:M (SiteCode as Primary & Foreign Key, short numeric)
Notification: Both directions
Record Count: 628 parent records, 50,000+ related records
Relationship Class: WNV_StagnantWaterSites_TO_WNV_SiteVisits
Goal:
I need to update the SiteRisk field (text: "Other", "Low", "Moderate", "High") in WNV_StagnantWaterSites based on related WNV_SiteVisits records where LarvacideRequest = 1 (Yes) in the last 12 months (SiteVisitDate field).

Logic:
0 records → SiteRisk = Low
1 record → SiteRisk = Moderate
2+ records → SiteRisk = High
Downgrades:
High → Moderate if no Yes records in 12 months
Moderate → Low if no Yes records in 12 months
Issue:
My attribute rule validates and saves, but SiteRisk does not update, no matter how I modify WNV_SiteVisits. Any help from an Attribute Rule Guru would be greatly appreciated! 🙏

// Relationship class name
var relationshipName = "WNV_StagnantWaterSites_TO_WNV_SiteVisits";

// Define the cutoff date for the last 12 months
var today = Now();
var twelveMonthsAgo = DateAdd(today, -12, "months");

// Fetch related site visit records (Child Features)
var relatedVisits = FeatureSetByRelationshipName($feature, relationshipName, ["LarvacideRequest", "SiteVisitDate"], false);

// Debugging: Log how many related visits were found
Console("🔍 Found " + Count(relatedVisits) + " related site visit records.");

// Filter visits where LarvacideRequest = 1 (Yes) AND occurred in the past 12 months
var recentLarvacideVisits = Filter(relatedVisits, "LarvacideRequest = 1 AND SiteVisitDate >= @twelveMonthsAgo");

// Count qualifying visits
var visitCount = Count(recentLarvacideVisits);

// Debugging: Log how many visits met the criteria
Console(":calendar: " + visitCount + " site visits in the past 12 months had LarvacideRequest = 1.");

// Determine new SiteRisk value based on visit count
var newSiteRisk = "";
if (visitCount == 0) {
    newSiteRisk = "Low";
} else if (visitCount == 1) {
    newSiteRisk = "Moderate";
} else if (visitCount >= 2) {
    newSiteRisk = "High";
}

// Fetch the parent feature (WNV_StagnantWaterSites)
var parentFeatures = FeatureSetByRelationshipName($feature, relationshipName, ["SiteRisk"], true);

// Ensure we have at least one parent
if (Count(parentFeatures) > 0) {
    var parent = First(parentFeatures);

    // Get the existing SiteRisk value
    var currentRisk = parent.SiteRisk;

    // Debugging: Log the existing SiteRisk before updating
    Console("🔄 Current SiteRisk: " + currentRisk);

    // Only update if the risk level actually changes
    if (currentRisk != newSiteRisk) {
        Console(" Updating SiteRisk from " + currentRisk + " to " + newSiteRisk);
        
        return {
            "edit": [
                {
                    "className": "WNV_StagnantWaterSites",
                    "updates": [
                        {
                            "objectID": parent.OBJECTID,
                            "attributes": {
                                "SiteRisk": newSiteRisk
                            }
                        }
                    ]
                }
            ]
        };
    } else {
        Console(":warning: No update needed. SiteRisk remains: " + currentRisk);
    }
} else {
    Console(" No parent found for this site visit.");
}

// No update needed
return null;

 

0 Kudos
1 Solution

Accepted Solutions
Jake_S
by Esri Contributor
Esri Contributor

@JamesBooth well I love to be proven wrong, even by me.

// Relationship class name
var relationshipName = "WNV_StagnantWaterSites_TO_WNV_SiteVisits";
var parentGlobalID;
var newSiteRisk = "";

// Define the cutoff date for the last 12 months
var today = Now();
var twelveMonthsAgo = DateAdd(today, -12, "months");

// Fetch related parent record (WNV_StagnantWaterSites)
var relatedParent = FeatureSetByRelationshipName($feature, "WNV_StagnantWaterSites_TO_WNV_SiteVisits", ["GlobalID"], false);

for (var parent in relatedParent) {
    parentGlobalID = parent.GlobalID;
    // Fetch related site visit records (Child Features)
    var relatedVisits = FeatureSetByRelationshipName(parent, "WNV_StagnantWaterSites_TO_WNV_SiteVisits", ["GlobalID","LarvacideRequest","SiteVisitDate"], false);

    // Debugging: Log how many related visits were found
    Console(" Found " + Count(relatedVisits) + " related site visit records.");

    // Filter visits where LarvacideRequest = 1 (Yes) AND occurred in the past 12 months
    var recentLarvacideVisits = Filter(relatedVisits, "LarvacideRequest = 1 AND SiteVisitDate >= @twelveMonthsAgo");

    // Count qualifying visits
    var visitCount = Count(recentLarvacideVisits);

    // Debugging: Log how many visits met the criteria
    Console(":calendar: " + visitCount + " site visits in the past 12 months had LarvacideRequest = 1.");

    // Determine new SiteRisk value based on visit count
    if (visitCount == 0) {
        newSiteRisk = "Low";
    } else if (visitCount == 1) {
        newSiteRisk = "Moderate";
    } else if (visitCount >= 2) {
        newSiteRisk = "High";
    }
}

return {
    'edit': [{
        'className': 'WNV_StagnantWaterSites',
        'updates': [{
            'globalID': parentGlobalID,
            'attributes': {
                "SiteRisk": newSiteRisk
            }
        }]
    }]
}


Try this applied to your in place of your original on the WNV_SiteVisits.

View solution in original post

12 Replies
Jake_S
by Esri Contributor
Esri Contributor

Hey James,

Couple things. In your return you are using the parent.OBJECTID (line 56), I would use a globalId. you can get this from your relationship class.

Also, I would just return, not return null (line 73). A simple return ends the expression evaluation, a return null, is trying to populate an objects field value with null. 

Start there, and let us know what happens.

~Jake

0 Kudos
Jake_S
by Esri Contributor
Esri Contributor

Line 13 is not doing what you think it is. FeatureSetByRelationshipName returns the related records for a given $feature, your parents that are return for that specific $feature.

If I'm assuming correctly you are trying to collect all the 
WNV_SiteVisits for each, filtered, for your WNV_StagnantWaterSites and then update.

If correct, you would either need this on your 
WNV_StagnantWaterSites with some sort of trigger or as a batch calculation.

Because this is a M:N relationship if applied to the WNV_SiteVisits you would have to go get all your WNV_StagnantWaterSitesparents that are related to that one $feature (FeatureSetByRelationshipName).

var parentGlobalList = []

var parentFeatures = FeatureSetByRelationshipName($feature, relationshipName, ["GLOBALID"], true);

for (var parent in parentFeatures){
    Push(parentGlobalList, parent.GLOBALID)
}

Once you have those WNV_StagnantWaterSites.GlobalIDs you would have to find a way to get back to the WNV_SiteVisits and get the related visits for each WNV_StagnantWaterSites GlobalID. Currently I do not believe there is a way to go backwards in a relationship. I'd love to be wrong and I hope the greater community can correct me.

If you can..... use that list to iterate over each globalid in the list to get all the related WNV_SiteVisits. 
Then filter. Get your count and push your edit up to a dictionary of globals

Push(parentUpdates, {
    'attributes': Dictionary(
        SiteRisk, newSiteRisk)
})


to then push your edits in your return dictionary. 







0 Kudos
JamesBooth
Regular Contributor

Thanks for your response Jake! I appreciate your assistance very much! I'm completely new to Arcade and I'll admit I'm using AI tools to assist, which is why I'm likely having issues. My relationship  between WNV_StagnantWaterSites and WNV_SiteVisits is actually 1:M. I have one WNV_StagnantWaterSites record with multiple WNV_SiteVisits records. Both are point feature classes. Parent represents the Stagnant Water Site. Child records are point locations surrounding the stagnant water site. Staff want to know specifically where students are collecting on a pond as an example. 

I tried your suggestions of using GlobalID instead of ObjectID and I also removed the return null, and just have return. Unfortunately, I still don't have my SiteRisk level changing. Even if I trigger the rule by applying a LarvacideRequest = "1" (Yes), nothing happens to the SiteRisk in the parent point feature layer. My updated syntax is at bottom. 

I also wonder what my execution parameters should be set at. This is what I have:

JamesBooth_0-1742242682482.png

 

// Define the related records from the WNV_SiteVisits layer
var relatedRecords = FeatureSetByRelationshipName($feature, "SDEDB1.GISADMIN.WNV_StagnantWaterSites_TO_WNV_SiteVisits");
var currentDate = Now();
var oneYearAgo = DateAdd(currentDate, -1, 'years');
var larvacideRequestCount = 0;

// Iterate through related records to count LarvacideRequest values of "1" (Yes) in the past 12 months
for (var record in relatedRecords) {
    if (record["LarvacideRequest"] == 1 && record["SiteVisitDate"] >= oneYearAgo) {
        larvacideRequestCount++;
    }
}

// Determine the new SiteRisk value based on the count of LarvacideRequest values
var newSiteRisk = "";
if (larvacideRequestCount == 0) {
    newSiteRisk = "Low";
} else if (larvacideRequestCount == 1) {
    newSiteRisk = "Moderate";
} else if (larvacideRequestCount >= 2) {
    newSiteRisk = "High";
}

// Update the parent record's SiteRisk field if it needs to be changed
if ($feature["SiteRisk"] != newSiteRisk) {
    return {
        "edit": [{
            "className": "SDEDB1.GISADMIN.WNV_StagnantWaterSites",
            "updates": [{
                "GlobalID": $feature["GlobalID"],
                "attributes": {
                    "SiteRisk": newSiteRisk
                }
            }]
        }]
    };
}

// End the expression evaluation if no update is needed
return;

 

 

0 Kudos
Jake_S
by Esri Contributor
Esri Contributor

@JamesBooth my apologies, I glossed over the initial part not realizing the relationship was 1:M.

Few questions,

Can you provide a screenshot of that relationship properties? 

catalog > right click relationship > properties

Also are you able provide empty data sets for the schema (create a copy and delete the contents)? If not that's fine.

I's want to test a solution.

~Jake


0 Kudos
JamesBooth
Regular Contributor

JamesBooth_0-1742311375858.png

 

0 Kudos
Jake_S
by Esri Contributor
Esri Contributor

@JamesBooth did a recording that may help. 

0 Kudos
JamesBooth
Regular Contributor

Thanks Jake! I will try this shortly later today and I'll let you know how it goes. I actually may not even need this rule anymore lol! Might be changing the workflow slightly so that user has more control on when SiteRisk needs changing. But I still want to see if I can get this working! So thank you! I'll keep you apprised! 

0 Kudos
Jake_S
by Esri Contributor
Esri Contributor

@JamesBooth well I love to be proven wrong, even by me.

// Relationship class name
var relationshipName = "WNV_StagnantWaterSites_TO_WNV_SiteVisits";
var parentGlobalID;
var newSiteRisk = "";

// Define the cutoff date for the last 12 months
var today = Now();
var twelveMonthsAgo = DateAdd(today, -12, "months");

// Fetch related parent record (WNV_StagnantWaterSites)
var relatedParent = FeatureSetByRelationshipName($feature, "WNV_StagnantWaterSites_TO_WNV_SiteVisits", ["GlobalID"], false);

for (var parent in relatedParent) {
    parentGlobalID = parent.GlobalID;
    // Fetch related site visit records (Child Features)
    var relatedVisits = FeatureSetByRelationshipName(parent, "WNV_StagnantWaterSites_TO_WNV_SiteVisits", ["GlobalID","LarvacideRequest","SiteVisitDate"], false);

    // Debugging: Log how many related visits were found
    Console(" Found " + Count(relatedVisits) + " related site visit records.");

    // Filter visits where LarvacideRequest = 1 (Yes) AND occurred in the past 12 months
    var recentLarvacideVisits = Filter(relatedVisits, "LarvacideRequest = 1 AND SiteVisitDate >= @twelveMonthsAgo");

    // Count qualifying visits
    var visitCount = Count(recentLarvacideVisits);

    // Debugging: Log how many visits met the criteria
    Console(":calendar: " + visitCount + " site visits in the past 12 months had LarvacideRequest = 1.");

    // Determine new SiteRisk value based on visit count
    if (visitCount == 0) {
        newSiteRisk = "Low";
    } else if (visitCount == 1) {
        newSiteRisk = "Moderate";
    } else if (visitCount >= 2) {
        newSiteRisk = "High";
    }
}

return {
    'edit': [{
        'className': 'WNV_StagnantWaterSites',
        'updates': [{
            'globalID': parentGlobalID,
            'attributes': {
                "SiteRisk": newSiteRisk
            }
        }]
    }]
}


Try this applied to your in place of your original on the WNV_SiteVisits.

JamesBooth
Regular Contributor

It works!! Fantastic. There does remain a small issue though and I'm trying to find it! The issue is deleting any WNV_SiteVisits records. If I create a new site visit and add a high larva count, which successfully triggers my "LarvacideRequest" field to become "1" (Yes), then the SiteRisk changes to moderate in the Parent, which is exactly what I want. But if I delete that WNV_SiteVisits record instantly, the SiteRisk level (value) remains the same in the Parent, and I would want it go back to 'Low' risk. I'm sure I'm missing something obvious. Add, update and delete are the triggers. And I have "exclude from application evaluation" checked because I got an error saying it needed to be checked given certain functions in the code (Edit()). Once that was checked, the attribute rule performs fine, with the exception of when I delete a WNV_SiteVisits record. SiteRisk remains the same.

0 Kudos