1

I am struggling to build the JSON hierarchy structure from the raw response JSON which I am getting from other API.

I want to generate a hierarchy structure from raw JSON Response on the basis of parent KPI and child KPI names relationship, which I am pulling from database for this example I have added the relationship table list below. I have Added a sample POC code in update, please check at the end.

Relationship list:

 // Sample relationship data
 var relationships = new List<Relationship>
        {
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "EquipAvailability", ChildKpiName = "total_downtime_hours", ParentKpiDisplayName = "Availability", ChildKpiDisplayName = "Total Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "scheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Scheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "unscheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Unscheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mttr", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTTR" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mtbf", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTFB" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mtbm", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTFB" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "Operational_Running_Hours", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "Operational Running Hours" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mttr", ChildKpiName = "total_downtime_hours_wts", ParentKpiDisplayName = "MTTR", ChildKpiDisplayName = "Total Downtime Hours of BD,NT" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mttr", ChildKpiName = "unscheduled_downtime_hours_bd_in_ops", ParentKpiDisplayName = "MTTR", ChildKpiDisplayName = "Total Downtime Hours of BD in Ops" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mtbf", ChildKpiName = "number_of_breakdowns", ParentKpiDisplayName = "MTFB", ChildKpiDisplayName = "Number Of Breakdowns" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mtbm", ChildKpiName = "Number of Maintainance Actions", ParentKpiDisplayName = "MTFB", ChildKpiDisplayName = "Number of Maintainance Actions" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Utilization", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Utilization" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Total Moves", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Total Moves" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Idle Hours", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Idle Hours" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Equipment Efficiency", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Equipment Efficiency" }
        };

Expected JSON:

[
  {
    "dimensions": {
      "vw_asset_mgmt.month_code": "202503",
      "vw_asset_mgmt.terminal_code": "T001"
    },
    "hierarchy": {
    "group_name": "Operations & Asset Performance",
      "EquipAvailability": {
        "display_name": "Availability",
        "value": 98.5,        
        "sub_levels": {
          "total_downtime_hours": {
            "display_name": "Total Downtime",
            "value": 120.5,
            "sub_levels": {
              "scheduled_downtime_hours": {
                "display_name": "Scheduled Downtime",
                "value": 50.0                
              },
              "unscheduled_downtime_hours": {
                "display_name": "Unscheduled Downtime",
                "value": 70.5
              }
            }
          }
        }
      },
      "ops_availability": {
        "display_name": "Operations Availability",
        "value": 95.0,
        "sub_levels": {
          "mttr": {
            "display_name": "MTTR",
            "value": 1.5,
            "sub_levels": {
              "total_downtime_hours_wts": {
                "display_name": "Total Downtime Hours of BD,NT",
                "value": 110.0
              }
            }
          },
          "mtbf": {
            "display_name": "MTBF", 
            "value": 500.0
            "sub_levels": {
              "number_of_breakdowns": {
                "display_name": "Number Of Breakdowns",
                "value": 5
              }
            }
          },
          "Operational_Running_Hours": {
            "display_name": "Operational Running Hours", 
            "value": 4000.0
          }
        }
      }
    
    }
  },
  {
    "dimensions": {
      "vw_asset_mgmt.month_code": "202502",
      "vw_asset_mgmt.terminal_code": "T002"
    },
    "hierarchy": {
    "group_name": "Operations & Asset Performance",
      "EquipAvailability": {
        "display_name": "Availability",
        "value": 97.0,
        "sub_levels": {
          "total_downtime_hours": {
            "display_name": "Total Downtime",
            "value": 140.0,
            "sub_levels": {
              "scheduled_downtime_hours": {
                "display_name": "Scheduled Downtime",
                "value": 55.0
              },
              "unscheduled_downtime_hours": {
                "display_name": "Unscheduled Downtime",
                "value": 85.0
              }
            }
          }
        }
      },
      "ops_availability": {
        "display_name": "Operations Availability",
        "value": 94.5,
        "sub_levels": {
          "mttr": {
            "display_name": "MTTR",
            "value": 1.8,
            "sub_levels": {
              "total_downtime_hours_wts": {
                "display_name": "Total Downtime Hours of BD,NT",
                "value": 130.0
              }
            }
          },
          "mtbf": {
            "display_name": "MTBF",
            "value": 480.0,
            "sub_levels": {
              "number_of_breakdowns": {
                "display_name": "Number Of Breakdowns",
                "value": 6
              }
            }
          },
          "Operational_Running_Hours": {
            "display_name": "Number Of Breakdowns"
            "value": 3900.0
          }
        }
      }
    }
  }
]

And I have below raw JSON from other API response:

[
  {
    "kpIs": [
      {
        "kpiName": "vw_asset_mgmt.EquipAvailability",
        "kpiValue": "100"
      },
      {
        "kpiName": "vw_asset_mgmt.total_downtime_hours",
        "kpiValue": "980"
      },
      {
        "kpiName": "vw_asset_mgmt.scheduled_downtime_hours",
        "kpiValue": "450"
      },
      {
        "kpiName": "vw_asset_mgmt.unscheduled_downtime_hours",
        "kpiValue": "90"
      },
      {
        "kpiName": "vw_asset_mgmt.ops_availability",
        "kpiValue": "96"
      },
      {
        "kpiName": "vw_asset_mgmt.mttr",
        "kpiValue": "980"
      },
      {
        "kpiName": "vw_asset_mgmt.total_downtime_hours_wts",
        "kpiValue": "40"
      },
      {
        "kpiName": "vw_asset_mgmt.unscheduled_downtime_hours_bd_in_ops",
        "kpiValue": "320"
      },
      {
        "kpiName": "vw_asset_mgmt.mtbf",
        "kpiValue": "87"
      },
      {
        "kpiName": "vw_asset_mgmt.number_of_breakdowns",
        "kpiValue": "100"
      },
      {
        "kpiName": "vw_asset_mgmt.Operational_Running_Hours",
        "kpiValue": "98"
      }
    ],
    "dimensions": [
      {
        "dimensionName": "vw_asset_mgmt.month_code",
        "dimensionValue": "202502"
      },
      {
        "dimensionName": "vw_asset_mgmt.terminal_code",
        "dimensionValue": "PEC2"
      }
    ]
  },
  {
    "kpIs": [
      {
        "kpiName": "vw_asset_mgmt.EquipAvailability",
        "kpiValue": "100"
      },
      {
        "kpiName": "vw_asset_mgmt.total_downtime_hours",
        "kpiValue": "98"
      },
      {
        "kpiName": "vw_asset_mgmt.scheduled_downtime_hours",
        "kpiValue": "877"
      },
      {
        "kpiName": "vw_asset_mgmt.unscheduled_downtime_hours",
        "kpiValue": "656"
      },
      {
        "kpiName": "vw_asset_mgmt.ops_availability",
        "kpiValue": "56.90"
      },
      {
        "kpiName": "vw_asset_mgmt.mttr",
        "kpiValue": "98.76"
      },
      {
        "kpiName": "vw_asset_mgmt.total_downtime_hours_wts",
        "kpiValue": "760.78"
      },
      {
        "kpiName": "vw_asset_mgmt.unscheduled_downtime_hours_bd_in_ops",
        "kpiValue": "0"
      },
      {
        "kpiName": "vw_asset_mgmt.mtbf",
        "kpiValue": null
      },
      {
        "kpiName": "vw_asset_mgmt.number_of_breakdowns",
        "kpiValue": "106"
      },
      {
        "kpiName": "vw_asset_mgmt.Operational_Running_Hours",
        "kpiValue": "435"
      }
    ],
    "dimensions": [
      {
        "dimensionName": "vw_asset_mgmt.month_code",
        "dimensionValue": "202503"
      },
      {
        "dimensionName": "vw_asset_mgmt.terminal_code",
        "dimensionValue": "PEC2"
      }
    ]
  }
]

I attempted to build a console POC application, but I'm not getting the expected hierarchy structure. Could you please review the code below and advise on what I might be doing wrong?

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;

public class KpiData
{
    public string KpiName { get; set; }
    public string KpiValue { get; set; }
}

public class Dimension
{
    public string DimensionName { get; set; }
    public string DimensionValue { get; set; }
}

public class KpiHierarchy
{
    public string DisplayName { get; set; }
    public double Value { get; set; }
    public Dictionary<string, KpiHierarchy> SubLevels { get; set; } = new Dictionary<string, KpiHierarchy>();
}

public class HierarchyResponse
{
    public Dictionary<string, string> Dimensions { get; set; }
    public Dictionary<string, KpiHierarchy> Hierarchy { get; set; }
}

public class Relationship
{
    public string KpiGroupName { get; set; }
    public string ParentKpiName { get; set; }
    public string ChildKpiName { get; set; }
    public string ParentKpiDisplayName { get; set; }
    public string ChildKpiDisplayName { get; set; }
}

public class Program
{
    public static void Main()
    {
        // Sample relationship data
        var relationships = new List<Relationship>
        {
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "EquipAvailability", ChildKpiName = "total_downtime_hours", ParentKpiDisplayName = "Availability", ChildKpiDisplayName = "Total Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "scheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Scheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "unscheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Unscheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mttr", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTTR" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mtbf", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTFB" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "Operational_Running_Hours", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "Operational Running Hours" }
        };

        // Sample input data (actual JSON response)
        var actualJson = new List<Dictionary<string, object>> {
            new Dictionary<string, object> {
                { "kpIs", new List<Dictionary<string, object>> {
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.EquipAvailability" }, { "kpiValue", "98.5" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.total_downtime_hours" }, { "kpiValue", "120.5" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.scheduled_downtime_hours" }, { "kpiValue", "50.0" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.unscheduled_downtime_hours" }, { "kpiValue", "70.5" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.ops_availability" }, { "kpiValue", "95.0" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.mttr" }, { "kpiValue", "1.5" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.total_downtime_hours_wts" }, { "kpiValue", "110.0" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.unscheduled_downtime_hours_bd_in_ops" }, { "kpiValue", "0.0" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.mtbf" }, { "kpiValue", "500.0" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.number_of_breakdowns" }, { "kpiValue", "5" } },
                    new Dictionary<string, object> { { "kpiName", "vw_asset_mgmt.Operational_Running_Hours" }, { "kpiValue", "4000.0" } }
                }},
                { "dimensions", new List<Dictionary<string, object>> {
                    new Dictionary<string, object> { { "dimensionName", "vw_asset_mgmt.month_code" }, { "dimensionValue", "202503" } },
                    new Dictionary<string, object> { { "dimensionName", "vw_asset_mgmt.terminal_code" }, { "dimensionValue", "T001" } }
                }}
            }
        };

        // Transform the data to hierarchical format
        var result = TransformJsonToHierarchy(actualJson, relationships);

        // Serialize the result into JSON and print it
        var jsonResult = JsonConvert.SerializeObject(result, Formatting.Indented);
        Console.WriteLine(jsonResult);
    }

    public static List<HierarchyResponse> TransformJsonToHierarchy(List<Dictionary<string, object>> actualJson, List<Relationship> relationships)
    {
        var hierarchyResponses = new List<HierarchyResponse>();

        foreach (var jsonItem in actualJson)
        {
            var kpIs = jsonItem["kpIs"] as List<Dictionary<string, object>>;
            var dimensions = jsonItem["dimensions"] as List<Dictionary<string, object>>;

            // Build the Dimensions dictionary
            var dimensionDict = dimensions.ToDictionary(d => d["dimensionName"].ToString(), d => d["dimensionValue"].ToString());

            // Initialize the hierarchy structure
            var hierarchy = new Dictionary<string, KpiHierarchy>();

            // Process the KPIs and organize them into the hierarchy
            foreach (var kpi in kpIs)
            {
                string kpiName = kpi["kpiName"].ToString().Split('.').Last(); // Use only the last part of the kpi name
                double kpiValue = double.TryParse(kpi["kpiValue"]?.ToString(), out double value) ? value : 0;

                // Find the relationship for the current KPI
                var relationship = relationships.FirstOrDefault(r => kpiName.Equals(r.ChildKpiName));
                if (relationship != null)
                {
                    // Ensure parent exists in hierarchy
                    if (!hierarchy.ContainsKey(relationship.ParentKpiName))
                    {
                        hierarchy[relationship.ParentKpiName] = new KpiHierarchy
                        {
                            DisplayName = relationship.ParentKpiDisplayName,
                            Value = 0, // This will be replaced later with the actual value
                            SubLevels = new Dictionary<string, KpiHierarchy>()
                        };
                    }

                    var parentKpi = hierarchy[relationship.ParentKpiName];

                    // Add the child KPI to its parent
                    parentKpi.SubLevels[relationship.ChildKpiName] = new KpiHierarchy
                    {
                        DisplayName = relationship.ChildKpiDisplayName,
                        Value = kpiValue
                    };
                }
            }

            // Add group name to the hierarchy
            var response = new HierarchyResponse
            {
                Dimensions = dimensionDict,
                Hierarchy = new Dictionary<string, KpiHierarchy>
                {
                    { "group_name", new KpiHierarchy { DisplayName = "Operations & Asset Performance", Value = 0 } }
                }
            };

            response.Hierarchy = hierarchy;

            hierarchyResponses.Add(response);
        }

        return hierarchyResponses;
    }
}

Updated POC Sample Application Code:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;

public class KPI
{
    public string KpiName { get; set; }
    public string KpiValue { get; set; }
}

public class Dimension
{
    public string DimensionName { get; set; }
    public string DimensionValue { get; set; }
}

public class KpiHierarchy
{
    public string DisplayName { get; set; }
    public double Value { get; set; }
    public Dictionary<string, KpiHierarchy> SubLevels { get; set; } = new Dictionary<string, KpiHierarchy>();
}

public class HierarchyResponse
{
    public Dictionary<string, string> Dimensions { get; set; }
    public Dictionary<string, KpiHierarchy> Hierarchy { get; set; }
}

public class Relationship
{
    public string KpiGroupName { get; set; }
    public string ParentKpiName { get; set; }
    public string ChildKpiName { get; set; }
    public string ParentKpiDisplayName { get; set; }
    public string ChildKpiDisplayName { get; set; }
}

public class AssetManagementData
{
    public List<KPI> KpIs { get; set; }
    public List<Dimension> Dimensions { get; set; }
}

public class Program
{
    public static void Main()
    {
        // Sample relationship data
        var relationships = new List<Relationship>
        {
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "EquipAvailability", ChildKpiName = "total_downtime_hours", ParentKpiDisplayName = "Availability", ChildKpiDisplayName = "Total Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "scheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Scheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "unscheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Unscheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mttr", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTTR" }            
        };

        var data = new List<AssetManagementData>
        {
            new AssetManagementData
            {
                KpIs = new List<KPI>
                {
                    new KPI { KpiName = "vw_asset_mgmt.EquipAvailability", KpiValue = "100" },
                    new KPI { KpiName = "vw_asset_mgmt.total_downtime_hours", KpiValue = "980" },
                    new KPI { KpiName = "vw_asset_mgmt.scheduled_downtime_hours", KpiValue = "450" },
                    new KPI { KpiName = "vw_asset_mgmt.unscheduled_downtime_hours", KpiValue = "90" },
                    new KPI { KpiName = "vw_asset_mgmt.ops_availability", KpiValue = "96" },
                    new KPI { KpiName = "vw_asset_mgmt.mttr", KpiValue = "980" },                   
                },
                Dimensions = new List<Dimension>
                {
                    new Dimension { DimensionName = "vw_asset_mgmt.month_code", DimensionValue = "202502" },
                    new Dimension { DimensionName = "vw_asset_mgmt.terminal_code", DimensionValue = "PEC2" }
                }
            },
            new AssetManagementData
            {
                KpIs = new List<KPI>
                {
                    new KPI { KpiName = "vw_asset_mgmt.EquipAvailability", KpiValue = "100" },
                    new KPI { KpiName = "vw_asset_mgmt.total_downtime_hours", KpiValue = "98" },
                    new KPI { KpiName = "vw_asset_mgmt.scheduled_downtime_hours", KpiValue = "877" },
                    new KPI { KpiName = "vw_asset_mgmt.unscheduled_downtime_hours", KpiValue = "656" },
                    new KPI { KpiName = "vw_asset_mgmt.ops_availability", KpiValue = "56.90" },
                    new KPI { KpiName = "vw_asset_mgmt.mttr", KpiValue = "98.76" }                    
                },
                Dimensions = new List<Dimension>
                {
                    new Dimension { DimensionName = "vw_asset_mgmt.month_code", DimensionValue = "202503" },
                    new Dimension { DimensionName = "vw_asset_mgmt.terminal_code", DimensionValue = "PEC2" }
                }
            }
        };

        // Convert the data to a dictionary format
        var jsonData = data.Select(item => new Dictionary<string, object>
        {
            { "kpIs", item.KpIs.Select(k => new Dictionary<string, object>
                {
                    { "kpiName", k.KpiName },
                    { "kpiValue", k.KpiValue }
                }).ToList() },
            { "dimensions", item.Dimensions.Select(d => new Dictionary<string, object>
                {
                    { "dimensionName", d.DimensionName },
                    { "dimensionValue", d.DimensionValue }
                }).ToList() }
        }).ToList();

        // Transform the data to hierarchical format
        var result = TransformJsonToHierarchy(jsonData, relationships);

        // Serialize the result into JSON and print it
        var jsonResult = JsonConvert.SerializeObject(result, Formatting.Indented);
        Console.WriteLine(jsonResult);
    }

    public static List<HierarchyResponse> TransformJsonToHierarchy(List<Dictionary<string, object>> actualJson, List<Relationship> relationships)
    {
        var hierarchyResponses = new List<HierarchyResponse>();

        foreach (var jsonItem in actualJson)
        {
            var kpIs = jsonItem["kpIs"] as List<Dictionary<string, object>>;
            var dimensions = jsonItem["dimensions"] as List<Dictionary<string, object>>;

            // Build the Dimensions dictionary
            var dimensionDict = dimensions.ToDictionary(d => d["dimensionName"].ToString(), d => d["dimensionValue"].ToString());

            // Initialize the hierarchy structure
            var hierarchy = new Dictionary<string, KpiHierarchy>();

            // Process the KPIs and organize them into the hierarchy
            foreach (var kpi in kpIs)
            {
                string kpiName = kpi["kpiName"].ToString().Split('.').Last(); // Use only the last part of the kpi name
                double kpiValue = double.TryParse(kpi["kpiValue"]?.ToString(), out double value) ? value : 0;

                // Find the relationship for the current KPI
                var relationship = relationships.FirstOrDefault(r => kpiName.Equals(r.ChildKpiName));
                if (relationship != null)
                {
                    // Ensure parent exists in hierarchy
                    if (!hierarchy.ContainsKey(relationship.ParentKpiName))
                    {
                        hierarchy[relationship.ParentKpiName] = new KpiHierarchy
                        {
                            DisplayName = relationship.ParentKpiDisplayName,
                            Value = 0, // This will be replaced later with the actual value
                            SubLevels = new Dictionary<string, KpiHierarchy>()
                        };
                    }

                    var parentKpi = hierarchy[relationship.ParentKpiName];

                    // Add the child KPI to its parent
                    parentKpi.SubLevels[relationship.ChildKpiName] = new KpiHierarchy
                    {
                        DisplayName = relationship.ChildKpiDisplayName,
                        Value = kpiValue
                    };
                }
            }

            // Add group name to the hierarchy
            var response = new HierarchyResponse
            {
                Dimensions = dimensionDict,
                Hierarchy = hierarchy
            };

            hierarchyResponses.Add(response);
        }

        return hierarchyResponses;
    }
}
3
  • This is a little too much. If you could condense your example to maybe two or three relationships with way lass raw data, this would be much easier to understand. Please try to extract the essence of the programming problem with your POC. Commented Mar 24 at 12:07
  • @GoodNightNerdPride Thanks for looking into the question, I will update the modified version. Commented Mar 24 at 12:17
  • @GoodNightNerdPride I have added the updated POC sample at the end, please have a look, Thanks! Commented Mar 24 at 12:29

1 Answer 1

1

According to the Expected JSON and Updated POC Sample Application Code, I create a sample, you could check it:

Classes: using JsonProperty to specify a different name for a property when it is serialized to or deserialized from JSON:

public class Relationship
{
    public string KpiGroupName { get; set; }
    public string ParentKpiName { get; set; }
    public string ChildKpiName { get; set; }
    public string ParentKpiDisplayName { get; set; }
    public string ChildKpiDisplayName { get; set; }
}

public class KPI
{
    public string KpiName { get; set; }
    public string KpiValue { get; set; }
}

public class Dimension
{
    public string DimensionName { get; set; }
    public string DimensionValue { get; set; }
}

public class AssetManagementData
{
    public List<KPI> KpIs { get; set; }
    public List<Dimension> Dimensions { get; set; }
}

public class Dimensions
{
    [JsonProperty("vw_asset_mgmt.month_code")]
    public string MonthCode { get; set; }

    [JsonProperty("vw_asset_mgmt.terminal_code")]
    public string TerminalCode { get; set; }
}

public class SubLevel
{
    [JsonProperty("display_name")]
    public string DisplayName { get; set; }

    [JsonProperty("value")]
    public double Value { get; set; }

    [JsonProperty("sub_levels")]
    public Dictionary<string, SubLevel> SubLevels { get; set; } = new();
}

public class Hierarchy
{
    [JsonProperty("group_name")]
    public string GroupName { get; set; }

    [JsonProperty("EquipAvailability")]
    public SubLevel EquipAvailability { get; set; }

    [JsonProperty("ops_availability")]
    public SubLevel OpsAvailability { get; set; }
}

public class TransformedAssetManagementData
{
    [JsonProperty("dimensions")]
    public Dimensions Dimensions { get; set; }

    [JsonProperty("hierarchy")]
    public Hierarchy Hierarchy { get; set; }
}

Then use the following code to convert the data: set NullValueHandling to Ignore so that properties with a default value aren't included in the JSON result.

    public static void Main()
    {
        // Sample relationship data
        var relationships = new List<Relationship>
        {
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "EquipAvailability", ChildKpiName = "total_downtime_hours", ParentKpiDisplayName = "Availability", ChildKpiDisplayName = "Total Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "scheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Scheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "total_downtime_hours", ChildKpiName = "unscheduled_downtime_hours", ParentKpiDisplayName = "Total Downtime", ChildKpiDisplayName = "Unscheduled Downtime" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mttr", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTTR" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mtbf", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTFB" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "mtbm", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "MTFB" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "ops_availability", ChildKpiName = "Operational_Running_Hours", ParentKpiDisplayName = "Operational Availability", ChildKpiDisplayName = "Operational Running Hours" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mttr", ChildKpiName = "total_downtime_hours_wts", ParentKpiDisplayName = "MTTR", ChildKpiDisplayName = "Total Downtime Hours of BD,NT" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mttr", ChildKpiName = "unscheduled_downtime_hours_bd_in_ops", ParentKpiDisplayName = "MTTR", ChildKpiDisplayName = "Total Downtime Hours of BD in Ops" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mtbf", ChildKpiName = "number_of_breakdowns", ParentKpiDisplayName = "MTFB", ChildKpiDisplayName = "Number Of Breakdowns" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "mtbm", ChildKpiName = "Number of Maintainance Actions", ParentKpiDisplayName = "MTFB", ChildKpiDisplayName = "Number of Maintainance Actions" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Utilization", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Utilization" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Total Moves", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Total Moves" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Idle Hours", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Idle Hours" },
            new Relationship { KpiGroupName = "Operations & Asset Performance", ParentKpiName = "Operational_Running_Hours", ChildKpiName = "Equipment Efficiency", ParentKpiDisplayName = "Operational Running Hours", ChildKpiDisplayName = "Equipment Efficiency" }
        };

        var data = new List<AssetManagementData>
        {
            new AssetManagementData
            {
                KpIs = new List<KPI>
                {
                    new KPI { KpiName = "vw_asset_mgmt.EquipAvailability", KpiValue = "100" },
                    new KPI { KpiName = "vw_asset_mgmt.total_downtime_hours", KpiValue = "980" },
                    new KPI { KpiName = "vw_asset_mgmt.scheduled_downtime_hours", KpiValue = "450" },
                    new KPI { KpiName = "vw_asset_mgmt.unscheduled_downtime_hours", KpiValue = "90" },
                    new KPI { KpiName = "vw_asset_mgmt.ops_availability", KpiValue = "96" },
                    new KPI { KpiName = "vw_asset_mgmt.mttr", KpiValue = "980" },
                    new KPI { KpiName="vw_asset_mgmt.total_downtime_hours_wts",KpiValue="110.0"},
                    new KPI { KpiName="vw_asset_mgmt.unscheduled_downtime_hours_bd_in_ops",KpiValue="0.0"},
                    new KPI { KpiName="vw_asset_mgmt.mtbf",KpiValue="500.0"},
                    new KPI { KpiName="vw_asset_mgmt.number_of_breakdowns",KpiValue="5"},
                    new KPI { KpiName="vw_asset_mgmt.Operational_Running_Hours",KpiValue="4000.0"}, 
                },
                Dimensions = new List<Dimension>
                {
                    new Dimension { DimensionName = "vw_asset_mgmt.month_code", DimensionValue = "202502" },
                    new Dimension { DimensionName = "vw_asset_mgmt.terminal_code", DimensionValue = "PEC2" }
                }
            },
            new AssetManagementData
            {
                KpIs = new List<KPI>
                {
                    new KPI { KpiName = "vw_asset_mgmt.EquipAvailability", KpiValue = "100" },
                    new KPI { KpiName = "vw_asset_mgmt.total_downtime_hours", KpiValue = "98" },
                    new KPI { KpiName = "vw_asset_mgmt.scheduled_downtime_hours", KpiValue = "877" },
                    new KPI { KpiName = "vw_asset_mgmt.unscheduled_downtime_hours", KpiValue = "656" },
                    new KPI { KpiName = "vw_asset_mgmt.ops_availability", KpiValue = "56.90" },
                    new KPI { KpiName = "vw_asset_mgmt.mttr", KpiValue = "98.76" }
                },
                Dimensions = new List<Dimension>
                {
                    new Dimension { DimensionName = "vw_asset_mgmt.month_code", DimensionValue = "202503" },
                    new Dimension { DimensionName = "vw_asset_mgmt.terminal_code", DimensionValue = "PEC2" }
                }
            }
        };


        var transformedData = data.Select(d => new TransformedAssetManagementData
        {
            Dimensions = new Dimensions
            {
                MonthCode = d.Dimensions.First(x => x.DimensionName == "vw_asset_mgmt.month_code").DimensionValue,
                TerminalCode = d.Dimensions.First(x => x.DimensionName == "vw_asset_mgmt.terminal_code").DimensionValue
            },
            Hierarchy = BuildHierarchy(d.KpIs, relationships)
        }).ToList();

        string json = JsonConvert.SerializeObject(transformedData, Newtonsoft.Json.Formatting.Indented,
        new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); //set NullValueHandling to Ignore so that properties with a default value aren't included in the JSON result.
        Console.WriteLine(json);
        Console.ReadLine();
    }
    public static Hierarchy BuildHierarchy(List<KPI> kpis, List<Relationship> relationships)
    {
        string groupName = relationships.FirstOrDefault()?.KpiGroupName ?? "Default Group";
        var hierarchy = new Hierarchy { GroupName = groupName };
        var subLevelLookup = new Dictionary<string, SubLevel>();

        foreach (var kpi in kpis)
        {
            string kpiName = kpi.KpiName.Replace("vw_asset_mgmt.", "");
            if (!double.TryParse(kpi.KpiValue, out double value)) continue;

            var matchingRel = relationships.FirstOrDefault(r => r.ParentKpiName == kpiName);
            var subLevel = new SubLevel { DisplayName = matchingRel?.ParentKpiDisplayName ?? kpiName, Value = value, SubLevels = new Dictionary<string, SubLevel>() };
            subLevelLookup[kpiName] = subLevel;
        }

        foreach (var rel in relationships)
        {
            if (subLevelLookup.TryGetValue(rel.ParentKpiName, out var parentSubLevel) && subLevelLookup.TryGetValue(rel.ChildKpiName, out var childSubLevel))
            {
                parentSubLevel.SubLevels[rel.ChildKpiName] = childSubLevel;
            }
        }

        foreach (var subLevel in subLevelLookup.Values)
        {
            if (subLevel.SubLevels.Count == 0)
            {
                subLevel.SubLevels = null;
            }
        }

        hierarchy.EquipAvailability = subLevelLookup.GetValueOrDefault("EquipAvailability");
        hierarchy.OpsAvailability = subLevelLookup.GetValueOrDefault("ops_availability");

        return hierarchy;
    }

The output as below:

result

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! The response Hierarchy class you have added contains specific class properties for each parent KPIs, which I don't want because then in future if more KPI added in the request I would need to do code changes. Please refer my response class model for dynamic kpis generation. It will be great help if you can adjust the code to match my requirement.
Your code is inconsistent, and the JSON format you want does not match your class definition. So please clarify your issue again.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.