Using FeatureSetBy functions in Arcade to drill-down to other layers and tables

63201
135
12-12-2018 02:24 PM

Using FeatureSetBy functions in Arcade to drill-down to other layers and tables

Today a great blog was posted by Paul Barker‌ on the new FeatureSet functions: What’s new with Arcade: Taking a stroll through FeatureSets (Part 1)  and also Kelly Gerrow‌ shared a great document on this topic: https://community.esri.com/community/gis/web-gis/arcgisonline/blog/2018/12/10/overlapping-features-i... . 

I didn't wanted to be left behind, so I thought I would share some examples using hydrants, the maintenance history and sub sectors and hydraulic sectors to show what you can achieve with the new Arcade functions released in ArcGIS Online on December 5th

Consider we have a web map with several layers and a table:

  • Hidrantes is a point layer with hydrants
  • Sub Sector is a polygon layer with a sub division of the area of interest
  • Sector Hidraulico is a polygon layer merging sub sectors into hydraulic sectors
  • Hist Mantenimiento is a table with the historic maintenance records for each hydrant

First of all, let’s apply some Arcade to visualize the hydrants based on their age. This was already possible in the previous release, so no new things here yet. We have the installation date stored in the field FECHAINSTALACION and we can use the DateDiff and Now functions to determine the age in years, which happens on the first two lines. After this we classify the value into significant ranges:

var fecha_inst = $feature.FECHAINSTALACION;
var edad = DateDiff(Now(), fecha_inst, "years");
var clase_edad = "";
if (edad > 50) {
    clase_edad = "Mayor a 50 años";
} else if (edad > 40) {
    clase_edad = "Entre 40 y 50 años";
} else if (edad > 30) {
    clase_edad = "Entre 30 y 40 años";
} else if (edad > 20) {
    clase_edad = "Entre 20 y 30 años";
} else if (edad > 10) {
    clase_edad = "Entre 10 y 20 años";
} else if (edad > 5) {
    clase_edad = "Entre 5 y 10 años";
} else {
    clase_edad = "Menor a 5 años";
}

return clase_edad;

The result is a text describing the age, for which we can define representative symbols (here using the Firefly symbols):

No fancy symbols for the other two polygon layers to avoid distracting the attention from the hydrants.

We would like to show in the pop-up window of each hydrant the list of all maintenance carried out on the hydrant. Both the maintenance history table and the hydrant layer contain the ID of the hydrant. The table also contains the dates and type of maintenance.

In the configuration of the pop-up of the hydrants we can add an Arcade expression like this one:

var tbl = FeatureSetByName($datastore,"Hist_Mantenimiento");
var codigo = $feature["COD_HIDRANTE"];
var sql = "COD_HIDRANTE = '" + codigo + "'";
Console(sql);
var mantenimientos = Filter(tbl, sql);
var cnt = Count(mantenimientos);
var historia = "";
if (cnt > 0) {
    historia = cnt + " Mantenimiento(s):";
    for (var mantenimiento in mantenimientos) {
        var txt_fecha = Text(mantenimiento.Fecha_Mantenimiento, ' - (Y/MM/DD) ');
        var txt_man = txt_fecha + mantenimiento.Mantenimiento;
        historia += TextFormatting.NewLine + txt_man;
    }
} else {
    historia = "No hay mantenimientos";
}

return historia; 

First of all, we access the table with the maintenance history and assign it to a variable tbl. Then we read the id of the current hydrant for which we want to create the pop-up. We define a SQL expression using the hydrant ID which is then used to filter the history table. The result is stored in a variable called mantenimientos. We can do a Count to obtain the number of maintenance carried out on the hydrant. If the count (cnt) is larger than 0, we start reading out the details and construct a list of maintenance including the date and type of maintenance.

The result will appear like this after we configure a simple custom html to show the attributes and result of the Arcade expression in the pop-up:

Now let’s continue with doing something with these new Arcade functions to get some data hydrants at the sub sector level. Since the number of maintenance obviously depend on the age of the hydrant, it would be nice to get some details on this at the sub sector level.

In the pop-up configuration of the sub sectors we can add the following Arcade expression:

var fs = FeatureSetByName($datastore,"Hidrantes");
var hidrantes = Intersects(fs, $feature);
var cnt = Count(hidrantes);

var edad_tot = 0;
for (var hidrante in hidrantes) {
    var edad = DateDiff(Now(), hidrante.FECHAINSTALACION, "years");
    edad_tot += edad;
}

var resultado = ""; 
if (cnt > 0) {
    var edad_media = edad_tot / cnt;
    resultado = "Hay " + cnt + " hidrantes en el sub sector";
    resultado += TextFormatting.NewLine + "La edad media de los hidrantes es de " + Round(edad_media, 2) + " años";
} else {
    resultado = "No hay hidrantes en el sub sector";
}

return resultado;

This expression will:

  • Access the Hydrants layer
  • Do an intersect with the current sub sector feature
  • Count the number of hydrants in the sub sector
  • Calculate the age for each hydrant and some all ages
  • Calculate the mean age of the hydrants and format the text with this information

The result will appear like this:

In this case there are 93 hydrants in the sub sector and the mean age is 20.64 years.

This is fun, but can we also show the names of the sub sectors that are contained by a hydraulic sector using these new Arcade functions? The answer is yes. Let’s add the following expression to the hydraulic sectors:

var fs = FeatureSetByName($datastore,"Sub Sector");
var subsectores = Intersects(fs, $feature);
var cnt = Count(subsectores);

var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
    resultado += TextFormatting.NewLine + subsector.IDSAP;
}

return resultado;

Just access the sub sectors layer and Intersect with the current hydraulic sector and voila…, rights? No, not so right. When you use an Intersect between two polygon layers, it will probably return too many features due to the fact that when two polygons have a matching boundary they will probably be included in the result, leading to more sub sectors than we want.

A way to avoid this is to use a small negative buffer on the hydraulic sector and do the Intersect with that buffered geometry like this:

var fs = FeatureSetByName($datastore,"Sub Sector");
var feature_buf = Buffer($feature, -100, 'meters');
var subsectores = Intersects(fs, feature_buf);
var cnt = Count(subsectores);

var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
    resultado += TextFormatting.NewLine + subsector.IDSAP;
}

return resultado;

Notice the Buffer with a negative distance that is created on line 2 and used on line 3 to get the rights polygons.

The resulting pop-up will show like this:

To be honest, I don’t like the unsorted list of sub sectors, so let’s order this list using OrderBy:

var fs = FeatureSetByName($datastore,"Sub Sector");
var feature_buf = Buffer($feature, -100, 'meters');
var subsectores = OrderBy(Intersects(fs, feature_buf), 'IDSAP ASC');
var cnt = Count(subsectores);

var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
    resultado += TextFormatting.NewLine + subsector.IDSAP;
}

return resultado;

Which will result in a sorted list of sub sectors:

I hope that these examples will help you to understand what is possible using Arcade with the latest update in ArcGIS Online, but before you jump in and start creating fabulous Arcade expressions I want to quote Uncle Ben (Spider-Man) for a moment:

With great power comes great responsibility...

As Paul Barker mentions in his blog, be careful and always validate that the performance of your expressions yield in an acceptable response time for your end-user. 

Comments

Hi Naomi Begg ,

Could you create a new question next time? This keep the document a bit cleaner and if others have the same question, they will be able to find an answer more easily.

So, what will probably be happening here is the way you added the service to the map. In case you use the map service and not specify the index of the layer, Arcade functionality will be limited:  https://maps.taupodc.govt.nz/server/rest/services/property/Reserve/MapServer

Configuring Arcade in the pop-up does not provide access to the $map and is restricted to the information in the current feature only:

If you add the index of the layer, it will not create a grouplayer and add the layer normally and Arcade functionality should be normal: https://maps.taupodc.govt.nz/server/rest/services/property/Reserve/MapServer/0

Access to $map:

Anonymous User

I can't get even a basic part of this to work. What is mean by "the exact name of the relationship"? Is that the name of the related table/layer in the feature service? Or the name of that related table/layer in the map itself?

I have a point layer of cases and a related table of household contacts. I can't even get this to work:

FeatureSetByRelationshipName($feature, 'householdcontacts', ['housecontactname', 'housecontactrelationship'], false);

This is the popup of my cases layer. So $feature is getting the point feature, 'householdcontacts' is the related table, and the two fields in brackets are the fields I want to return. But the Test shows Null and the popup shows nothing.

Hi Nathan Fazer , 

Let me try and answer the questions you posted:

What is mean by "the exact name of the relationship"? Is that the name of the related table/layer in the feature service? Or the name of that related table/layer in the map itself?

If the layer where you are configuring the pop-up has a relationship to another layer or table, you can navigate through the interface and get to the related features. Click on ">" next to the "$feature":

Then you will scroll down and below the attributes of the feature you will find "Related records". Click on the ">" next to that:

This will list all the related tables and feature layers:

Click on the blue link to insert the correct code into the expression builder:

I have a point layer of cases and a related table of household contacts. I can't even get this to work:

FeatureSetByRelationshipName($feature, 'householdcontacts', ['housecontactname', 'housecontactrelationship'], false);

Use the navigation as explained above to see of the name of the relationship is correct.

This is the popup of my cases layer. So $feature is getting the point feature, 'householdcontacts' is the related table, and the two fields in brackets are the fields I want to return. But the Test shows Null and the popup shows nothing.

The function "FeatureSetByRelationshipName" will return a featureset. It may show when you test the expression in the expression builder, but it will not be shown in the pop-up. You will have to extract the relevant information and construct the string that you want to show in the pop-up.

Anonymous User

Xander, your workflow worked in my test setup in AGO, but it appears to not be working the same in Portal 10.8.1. In Portal when I follow your workflow, I'm just getting FeatureSetByRelationshipName($feature,""). My Portal setup is tied to data in SQL with all these relationships in the database. When I try to manually add in the parameters I'm again met with Null and nothing happening.

I named all my map layers the same in my Portal map as the working AGO map and when I run Test I get: Execution Error:Invalid Parameters for Count

Is there a reason this workflow works in AGO but not Portal?

Hi Nathan Fazer ,

The single and double quotes are mostly interchangeable, although it is better not the mix them too much. Therefore, you will see a lot of examples that use either one or the other or both. I can imagine that this can be confusing. It is best to rely on the interface to help you get the correct syntax for the expression. However, in your case you need to add additional parameters as you already did (although the "false" as the end is missing).

I would probably use this for your case:

FeatureSetByRelationshipName($feature, "Cases_householdcontacts", ["housecontactname", "housecontactrelationship"], false);

Anonymous User

Appreciate the help (and quick replies). I probably should have provided all the relevant info. Here's the entire code I got working in AGO based on what I've found here and in other posts. Replicating this in Portal however, gives me the error invalid parameters for count. Everything is the same - layer names, relationships, etc. So even though I made progress in my testing in AGO, this actually has to be in Portal as it's for our Health Department.

var fs = FeatureSetByRelationshipName($feature,"Cases_householdcontacts", ['housecontactname', 'housecontactrelationship'], false);
var result = "Household Contacts:";
var cnt = Count(fs);
if (cnt > 0) {
    // start loop through related records
    for (var f in fs) {
        // for each f (=feature) in related features, add contacts to the result
        result += TextFormatting.NewLine + f.housecontactname;
    }    
} else {
    // overwrite result with text to indicate that there are no contacts
    result = "No household contacts";
}

return result;

So now I'm baffled as to why this works in AGO but not in Portal.

Hi Nathan Fazer ,

Quick questions... is your Enterprise 10.8 or later? The FeatureSetByRelationshipName was introduced in Arcade version 1.8 and became available starting with Enterprise 10.8. 

If you have 10.7.x you could use FeatureSetByName together with a filter on the key field to get the related records.

Have a look at:

Anonymous User

Hi Xander

Yep I just updated to 10.8.1 this past Friday from 10.8, so this should be working. I've got an open case right now with Esri so I'll pass this info along to them and see what they may be able to figure out. I appreciate the help. It works pretty well in AGO, unfortunately this project is in Portal. My other thought was to try a test on our Portal with a hosted service and see if that makes a difference, instead of referencing data in our SQL.

Hi nfazer_midlandcounty ,

If Esri support provides a solution please share it here so that other user may benefit from it too. 

Hi Xander Bakker i have created a map series from an Arcgis online Map in Arcgis pro based on a series of polygons and i wanted to count the number of intersecting points on another layer. The arcade expression works fine on ArcGIS online but  in the map series it does not recognise the layer i reference in the featuresetbyname function when i use $datastore. From you responses above it sounds like there is no way to reference ArcGIS online layers in an  Arcgis pro map series using arcade or am i missing something? 

Hi Paul Sweeney ,

Where do you want to calculate the count? Is that in a Field Calculation? Are the polygon and point layer part of the same feature service (are they in the same $datastore)? I haven't worked with Arcade in combination with map series, so I don't have a straight answer for you.

i want it to be an expression built into the map series. When you select dynamic text you have the option to use an arcade expression if you are inserting an attribute value or a table. They are not in the same feature service,  i had not realised that was what the $datastore represented on Arcgis online but it makes sense now. it would be useful if you could essentially show your pop up on Arcgis online  in a map series. 

Anonymous User

Xander, I sent Esri tech support my sample data with related tables and related feature classes. They brought it into a SQL environment and published it to Portal and sent me an email that this - FeatureSetByRelationshipName($feature,"",["householdcontacts_casename"]) - resulted in a successful test. When I do it, it's empty. What I found odd is in his test there is nothing in the quotes between $feature and [fieldname]. I thought that was a crucial piece of making this work is the relationship name needed to be there, like this - FeatureSetByRelationshipName($feature, "Cases_householdcontacts", ["housecontactname"].

So now I'm really confused how Esri tech support was able to get a successful test missing information and I can't get anything trying 10 variations. This seems so simple yet I either get errors or empty results.

Hi Paul Sweeney ,

I am not really aware of what limitations there are when using Arcade in the dynamic text. Maybe you could use other functions like Portal and FeatureSetByPortalItem to get access to the data you need. You can also pre-calculate the data in a new field and use that static information in the map series. 

Regarding your comment on using the pop-up in the map series... a pop-up will only be present when you click on a feature. You could use labeling, but Arcade functions in this profile are very limited.

Hi Nathan Fazer ,

I think they managed to not only the confuse you but me as well. The second parameter is not optional, and providing an empty string is not documented in the help. Maybe if you have a single relationshipclass, providing an empty string just takes the first one available and everything works, but I see no documentation to aid that assumption. Let me run some tests and get back to you.

Hi Nathan Fazer ,

I did some tests and providing an empty string in the FeatureSetByRelationshipName did not work for me. I don't think it is the correct way of using the function. 

Anonymous User

Appreciate your efforts Xander. I had a phone call with Support and I didn't quite understand their explanation on that second parameter - I was told if it's from SQL it can be blank but if its hosted it needs it? I think you are correct in that if the layer only has one relationship, empty quotes works because it doesn't need to search through multiple relationships. Not sure why it worked for him though and not on my setup.

I did test my data by publishing as a hosted service in my Portal and the Arcade expressions all work wonderfully. So I've narrowed it down to something with SQL. My options are to backup my data, blow away the current SQL DB, create a new one and try to set this up again and see if that helps. My other option is to publish my data as it is now as a hosted service and forget trying to use SQL. I'm debating the pros/cons of doing that as I don't want to get in the middle of this data effort and hit limitations with the route I chose. Honestly nobody is editing the SQL data directly - it would all be done through Portal and Survey123, so hosted may be the way to go. Especially if this Arcade stuff works fine on the hosted data.

This project needs to be deployed next week so if I can't get this expression stuff figured out it won't prevent the project from moving forward, I was just hoping to get something simple working.

Anonymous User

Hey Xander, 

Is it possible to use arcade to reference data from another gdb? 

For example, we are trying to create an attribute rule (for lines and points), where by they acquire an attribute of an intersecting polygon from another geodatabase. We are wanting to create this rule using arcpy. I've gotten it to work using $datastore with a polygon inside the same gdb, but we'd like to be able to cross reference databases. Any idea?

Hi Michael Layne , 

Good question. As far as I know, the Attribute Calculation Rule profiel only has support for $datastore, which makes me believe that it is not possible if the information is not in the same datastore. Maybe in the feature support for other data sources will be added so that this will be possible. For now, if possible, it might be good to include the other layer in the same datastore to be able to use Attribute Rules and Arcade or schedule a task (python script) to update the information at a certain frequency. 

Hi Xander,

Thank you for this great example and all your answers, it's an Arcade goldmine.

I'm trying to replicate the popup functionality in one of my own webmap on a portal, but I keep running into the same error: "Execution Error:Runtime Error: Variable must be declared before it is used.."  but I can't see any undeclared variables in the code. 

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

var fs = FeatureSetByName($map, "NaO", ["skovnavn"]);
var fsIntersects = Intersects(fs, $feature);
var cnt = Count(fsIntersects);
//var fsDistincts = Distinct(fsIntersects,["skovnavn"]);
//var cnt = Count(fsDistincts);
var resultat = "";
if (cnt > 0){
for (var fsIntersect in fsIntersects){
var txt_skovnavn = Text(fsIntersect.skovnavn);
resultat += txt_skovnavn + ", "
}
} else {
resultat = "Hvorfor er der ingen skove på denne enhed?";
}
resultat = Text(Left(resultat,Count(resultat)-2)) + "."
return resultat;

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

The map is shared on: https://gis.nst.dk/portal/home/webmap/viewer.html?webmap=b8be8d61e775431c8f5a92887b49860e

I have tried almost the same code in ArcGIS Pro ($datastore instead of $map in the first line) to calculate a field and in this environment I don't get any errors.

Note: I tried the code on ArcGIS Online and it ran without any problems, so I assume that it must be the portal security kicking in somehow.

Hi @XanderBakker ,

Thanks for a great example and workflow. I am basically trying to replicate this workflow, but I get stuck when trying to summarize the info in my subsectors in MapViewer Beta in AGOL. When using MapViewer Classic in Portal it works.

I wanted to use MapViewer Beta for this, and since our Portal is currently on 10.8 I shared the data through a distributed collaboration to our AGOL account. I get the previous expressions for summarizing related table records for individual assets to work.

In my Arcade window in MapViewer beta it all looks great and I get a correct looking result, in my pop-ups however, I only get a result when there is no objects in the sub-sector.

RickardNasstrom_0-1616685152786.png

This is what it looks like when I write my expression. - It recognises dates and the number of objects.

I am quite novice in terms of using Arcade, but my guess here is that it has something to do with me not accessing the data correctly, however it seems strange to me that I get a result in the Arcade window? 

Here is my code: (basically just copy/paste frome yours)

var fs = FeatureSetByName($map,"Belysningsstolpar_Gävle");
var belysning = Intersects(fs, $feature);
var cnt = Count(belysning);
Console(cnt)

var age_tot = 0;
for (var lyse in belysning) {
var age = DateDiff(Now(), lyse.Installationsdatum, "years");
age_tot += age;
Console(age_tot)
Console(lyse.Installationsdatum)
}

var resultat = "";
if (cnt > 0) {
var age_media = age_tot / cnt;
resultat = "Det finns " + cnt + " Belysningsstolpar i subsektorn";
resultat += TextFormatting.NewLine + "Medelåldern är " + Round(age_media, 2) + " år";
} else {
resultat = "Inga belysningsstolpar i subsektorn";
}

return resultat;

Could it be accessing the data or is there something different when you use MapViewer Beta?

Best Regards

Rickard

Hi @RickardNasstrom ,

It is strange that it would not work in Map Viewer Beta, since it should. I just did a test with the example that I constructed for this post and it works as expected in the Map Viewer Beta:

XanderBakker_2-1616688123461.png

XanderBakker_1-1616688099759.png

XanderBakker_0-1616688086090.png

The first thing where I would look at is renaming the layer and not using special characters provides a valid result. I don't see anything else that could explain this behaviour.

 

Thanks for testing and your quick reply. I just tried with the same feature layer in AGOL Classic MapViewer where it works. 

This is how my pop-up looks in Beta 

RickardNasstrom_0-1616688703080.png

 

And here is in classic:

RickardNasstrom_1-1616688793584.png

I'll try to get rid of my special charachters, see if it helps. 

Thanks for a great guide!

 

Is it possible to reference other layers in ArcGIS Pro project? I can refer to other layers in a webmap but how about ArcGIS Pro map or project? I am looking for a way to calculate distances to objects on other layers in ArcGIS Pro field calculator. 

Hi @JussiLehtonen ,

The Field Calculation profile only supports $feature and $datastore. So this means that the data you want to use in the calculation must be in the same $datastore (FGDB, EGDB, hosted feature layer, etc). Although the FeatureSetByPortalItem is available, I haven't been able to use it successfully in ArcGIS Pro for a field calculation.

With the latest version of ArcGIS Dashboards, you can create featuresets on the fly with Arcade and use them as data source. This uses FeatureSetByPortalItem to access the data, so I assume that it a matter of time it will be able to use data from different data sources in an Arcade expression to calculate a field.

hola  quería generar un atributo que hiciera el conteo de la cantidad de registros de una operación de  válvulas . ( estas controlan el paso del agua en un acueducto )  utilizando el ejemplo de Hidrantes que tienen en la web, sin embargo me genera error y no se como solucionarlo, el código es:
 
// Inicialmente, se relaciona la dbase table que almacena los registros de operaciones realizadas a la válvula
var tbl FeatureSetByRelationshipName($datastore,"OperacionValvula");

// Se relaciona el atributo en el feature Class que actúa como llave entre el feature y la tabla relacional
var codigo = $feature["GlobalID"];

// Se establece el query que se creará en la tabla para filtrar los registros de operaciones de la válvula seleccionada
var sql = "ID_GLOBAL = '" + codigo + "'";

// Se generan los filtros
Console(sql);
var operaciones = Filter(tbl, sql);

// Se realiza el conteo de operaciones
var cnt = Count(operaciones);
var historia = "";
if (cnt > 0) {
    historia = cnt + " Operaciones realizadas a la válvula:";
    }
} else {
    historia = "No hay operaciones realizadas a la válvula";
}

return historia;  

 
El feature tiene un campo llamado "OPERACION_QUE_REALIZA" que le da la simbología a las válvulas, este atributo es el único que se debe diligenciar en el feature antes de diligenciar la información en la tabla relacional.
 
Adicionalmente, quería hacer el conteo de válvulas por comuna ( Localidad)  y la siguiente expresión me genera error:
 
var fs = FeatureSetByName($map,"Valvulas_IBAL_2021");
var valvulas = Intersects(fs, $feature);
var cnt = Count (valvulas);

if (cnt > 0) {
        resultado = "Hay " + cnt + " valvulas en la comuna";
   
} else {
    resultado = "No hay valvulas en la comuna";
}

return resultado;
 
 
agradezco la ayuda

Hola @Carlos_AndresCamacho_Acuña , cómo estás?

Revisando el primer bloque me di cuenta de algunos errores pequeños. Al comienzo el signo "=" después de "var tbl ". Y hacia el final sobraba una corcheta.

// Inicialmente, se relaciona la dbase table que almacena los registros de operaciones realizadas a la válvula
var tbl = FeatureSetByRelationshipName($datastore,"OperacionValvula");

// Se relaciona el atributo en el feature Class que actúa como llave entre el feature y la tabla relacional
var codigo = $feature["GlobalID"];

// Se establece el query que se creará en la tabla para filtrar los registros de operaciones de la válvula seleccionada
var sql = "ID_GLOBAL = @codigo";
Console(sql);

// Se generan los filtros
var operaciones = Filter(tbl, sql);

// Se realiza el conteo de operaciones
var cnt = Count(operaciones);
var historia = "";
if (cnt > 0) {
    historia = cnt + " Operaciones realizadas a la válvula:";
} else {
    historia = "No hay operaciones realizadas a la válvula";
}

return historia;  

 

En la segunda parte te falta declarar el variable resultado:

var fs = FeatureSetByName($map, "Valvulas_IBAL_2021");
var valvulas = Intersects(fs, $feature);
var cnt = Count(valvulas);

var resultado = "";
if (cnt > 0) {
    resultado = "Hay " + cnt + " valvulas en la comuna";
} else {
    resultado = "No hay valvulas en la comuna";
}

return resultado;

 

 

Hi

I have been trying for months to get the parcel details from a property layer to autopopulate in the popup for a data capture layer for a weed point...

I was provided the following to use, however all it returns is "Execution Error:Invalid Parameters for Count" and I have no idea why or how to fix. I'm losing my mind!! Can someone please help?

 

var layerName = $layer;
var fieldName = "parcel_title";

var set = FeatureSetByName($map,"council_data.property")

function getAttributeFromLargestArea(feat, set, field) {
var items = intersects(set, feat);
var counts = count(items);

if (counts == 0) {
return { 'errorMessage': 'No intersection found' };
}

if (counts == 1) {
var result = first(items);

return result[field];
}

var largest = -1;
var result;

for (var item in items) {
var size = area(intersection(item, feat));

if (size > largest) {
largest = size;
result = item[field];
}
}

return result;
}

getAttributeFromLargestArea($feature, set, fieldName)

Hi @KylieRyan ,

Not sure what might be going wrong with the expression. The only thing I can think of is it doesn't find the layer in the map (check the exact name) or the feature does not intersect with any features from the featureset or there are differences in coordinate systems between the feature and the featureset. 

I reorganized the expression a bit, but no big changes:

function getAttributeFromLargestArea(geom, fs, field) {
    var items = Intersects(fs, geom);
    var counts = Count(items);

    if (counts == 0) {
        return {'errorMessage': 'No intersection found'};
    }

    if (counts == 1) {
        var result = First(items);
        return result[field];
    }

    var largest = -1;
    var result;

    for (var item in items) {
        var size = Area(Intersection(item, geom));

        if (size > largest) {
            largest = size;
            result = item[field];
        }
    }

    return result;
}

// var layerName = $layer;
var fieldName = "parcel_title";
var fs = FeatureSetByName($map, "council_data.property");

return getAttributeFromLargestArea(Geometry($feature), fs, fieldName);

Hi @XanderBakker !

Thank you so much for your help! I looked into it a bit further and could only thing I could come up with was that the layer (being the Council's main property information layer) was not a feature layer but an map image layer - would that be the issue?

Hi Xander,

 

I currently am trying to populate dashboard widgets with info from a related table (and some info from the primary table) using the code below: 

 

var features = [];
var feat;
for (var v in valvefs){
    var relatedrecords = OrderBy(FeatureSetByRelationshipName(v, 'System_Valve_Inspection', ["insdate", "turns", "fintorque"],false),'insdate DES');
    var recentrecord = First(relatedrecords);
   if (Count(relatedrecords)>0){
         
        var feat = {
           attributes: {
               'assetid': v["assetid"],
               'insdate': recentrecord["insdate"],
               'diameter': v["diameter"],
               'turns': recentrecord["turns"],
               'fintorque': recentrecord["fintorque"],
           }
       }
       Push(features,feat);
   };
};   
var joinedDict = {
    fields: [
     { name: "assetid", type: "esriFieldTypeString" },
     { name: "insdate", type: "esriFieldTypeDate" },	
     { name: "fintorque", type: "esriFieldTypeDouble" },
     { name: "turns", type: "esriFieldTypeDouble" },
     { name: "diameter", type: "esriFieldTypeDouble" },
    ],
    geometryType: '',
    features: features
};
return FeatureSet(Text(joinedDict))

 

This code (as it stands right now) returns an empty resultset. Could I try something similar to what you have here, or does the output of a data expression HAVE to be a featureset? 

Thanks so much for any help!

Hi @TSmith ,

Sorry for the delay in my reply. 

My first guess would be the date. You need to convert it to epochs to ensure that it is taken as a date when creating the featureset.

You can do something like:

var epoch = DateDiff(insdate, Date(1970, 0, 0));

Hi @XanderBakker 

I am attempting to pull attribute information from a related table, although I am not getting an error but rather a blank result. Is FeatureSetByRelationshipName compatible in ArcGIS Online going against a 10.5.1 ArcGIS Server map service?

Thanks,

Jared

Hi @jschuckert ,

Good question... The FeatureSetByRelationshipName function is available in ArcGIS Online, but was not available in ArcGIS Enterprise at version 10.5.1. This might make the request to the server invalid or perhaps the response is not getting through correctly. Have you verified if there is something in the logs of ArcGIS Server?

Hi @XanderBakker 

This post has been super helpful. I've read through it and all the comments. I have a very similar use case but need a slightly different output. 

I have a polygon layer of buildings and a table of category codes that are included in a relationship class. The field that links them is an ID field which is called "UID" in the buildings layer and "UID_Child" in the category code table. I am trying to edit my output so that in the case of multiple occurrences of the same category code within one building, that code would be listed once along with a count of how many times it occurs, rather than listing duplicate codes. Here's my current code: 

//identify related table data
var related_table = FeatureSetById($datastore, "11");

//filter relate table for records matching unique ID
var filter_query = "UID_Child = '" + $feature["UID"] + "'";
Console('filtering related data records')
var related_data_filtered = Filter(related_table, filter_query);

//count records matching UID in related table 
var related_data_filtered_count = Count(related_data_filtered);
var output = []
Console('records filtered: '+ related_data_filtered_count)

//push catcode value from related data table to output 
if (related_data_filtered_count > 0) {
  for (var related_data_row in related_data_filtered) {
    Push(output, related_data_row.CATCODE)
  }
} else {
  return "No Related Records."
}
Console(output)

And here's what the popup looks like: 

ChrisMartin123_0-1711139615548.png

 

So for this feature for example, I would want it to read "610112 (10 or however many times it occurs)" I think I need to use a for loop to count how many times each catcode occurs. I've tried a ton of different variations with no success. I'll put one sample below. Do you have any ideas?

var filter_query = "UID_Child = '" + $feature["UID"] + "'";
var related_data_filtered = Filter($datastore["11"], filter_query);
var related_data_filtered_count = Count(related_data_filtered);

Console("Filtered data count: " + related_data_filtered_count);

var catcodeCounts = {}; // Object to store counts of each unique CATCODE

if (related_data_filtered_count > 0) {
  Console("Processing related records...");
  
  // Loop through the filtered related features
  for (var i = 0; i < related_data_filtered_count; i++) {
    var feature = related_data_filtered[i];
    var catcode = feature["CATCODE"]; // Accessing the CATCODE attribute directly
    
    // Increment count for the current CATCODE or initialize count to 1
    if (!catcodeCounts[catcode]) {
      catcodeCounts[catcode] = 1;
    } else {
      catcodeCounts[catcode] += 1;
    }
    
    Console("Processed CATCODE: " + catcode);
  }
  
  // Construct output with counts of each unique CATCODE
  var output = "";
  for (var catcode in catcodeCounts) {
    output += "CATCODE " + catcode + ": " + catcodeCounts[catcode] + "\n";
  }
  
  Console("Output: \n" + output);
  return output;
}

Console("No related records found.");
return "No Related Records.";

 

 

 

 

Version history
Last update:
‎12-12-2021 03:46 AM
Updated by: