cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Learn all about PTC Community Badges. Engage with PTC and see how many you can earn! X

Recursive Services for Metric Roll-ups

No ratings

This is a useful trick for rolling up metrics in Thingworx across various levels of a hierarchy by using Networks, ThingShapes, and recursive service definitions.

Say that you have a hierachy of Things in your model such as a Global view, a Region view, and a Store view -- this could be a Mfg Plant, a Building, an Asset, etc; whatever the core metric producing Thing is in your model -- where your Store has KPIs that you want to roll up across regions and globally.

First, create a template for each of your hierarchical levels. In my case it is a GlobalTemplate, RegionalTemplate, and StoreTemplate. Add a property to your StoreTemplate that will be the KPI.

Now, create a Thing for the Globe, and each of your Regions and Stores. Add them to a hierachical Network as such:

Now, we need to create a ThingShape to aggregate our KPIs and apply it to the Global, Regional, and Store template.

Now we will define a recursive funciton on our ThingShape called GetKPI ​and define it with the following:

//define our base case, when the thing template we are on is the lowest level of our hierarchy, in this case the StoreTemplate

if (me.thingTemplate == "StoreTemplate") {

    //in our base case, the result is just the property for the metric we want to aggregate

    result = me.someMetric

} else {

    //otherwise, we are at some other level in the hierarchy and we need to get our child connections from the network

    //this gets all the things below us in the network

    var params = {

        name: me.name /* STRING */

    };

    // result: INFOTABLE dataShape: NetworkConnection

    var network = Networks["Network"].GetChildConnections(params);

    //loop through each of the things below us in the hierarchy and recursively add the result of GetKPI() to our result

    result = 0;

    for each (var row in network.rows) {

   

        result += Things[row.to].GetKPI();

    }

}

This is a simple case of just summing up a single property, but we can take this further using the Union and Aggregate snippets provided by thingworx to do other kinds of summarization. First add a new property called someAvgMetric ​to our StoreTemplate, and define a new service GetKPIProperties as such, with an InfoTable result, on the StoreTemplate

varparams = {

    propertyNames: {"items": ["someMetric", "someAvgMetric"]} /* JSON */

};

// result: INFOTABLE dataShape: "undefined"

var result = me.GetNamedProperties(params);

Now, define a new service on our ThingShape to utilize this service as our base case, and aggregate the resulting InfoTable when necessary. We'll call this service GetKPIAggregates:

//define our base case

if (me.thingTemplate == "StoreTemplate") {

    //this function will be on the StoreTemplate, and returns the base infotable

    result = me.GetKPIProperties()

} else {

    //grab our network

    var params = {

        name: me.name /* STRING */

    };

    // result: INFOTABLE dataShape: NetworkConnection

    var network = Networks["Network"].GetChildConnections(params);

    //need to create an empty infotable to union into. I glossed over this, but you'll need a datashape here

    //create empty infotable

    var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({ infoTableName: "InfoTable", dataShapeName: "KPIDataShape" });

    //loop through and union each of our results to our new infotable

    for each (var row in network.rows) {

        var params = {

            t1: result /* INFOTABLE */,

            t2: Things[row.to].GetKPIAggregates() /* INFOTABLE */

        };

        var result = Resources["InfoTableFunctions"].Union(params);

    }

    //aggregate each of our fields

    var params = {

        t: result /* INFOTABLE */,

        columns: "someMetric,someAvgMetric" /* STRING */,

        aggregates: "SUM,AVERAGE" /* STRING */,

        groupByColumns: undefined /* STRING */

    };

    // result: INFOTABLE

    var result = Resources["InfoTableFunctions"].Aggregate(params);

    //need to loop through each of our field names and make them match our base infotable

    // infotable datashape iteration

    var dataShapeFields = result.dataShape.fields;

    for (var fieldName in dataShapeFields) {

        var stringName = dataShapeFields[fieldName].name;

        var params = {

            t: result /* INFOTABLE */,

            from: stringName /* STRING */,

            to: stringName.split("_")[1] /* STRING */

        };

        // result: INFOTABLE

        var result = Resources["InfoTableFunctions"].RenameField(params);

    }

}

Now, in our mashups, we can use a DynamicThingShape and call our GetKPIs service at any level in our network, and our data will be aggregated correctly for whatever level we are at in the hierarchy!

Version history
Last update:
‎Aug 10, 2017 05:22 PM
Updated by:
Labels (1)