skip to Main Content

I have the following structure :

var content = {
    "id": "RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc",
    "name": "FI-1058-0517",
    "category": "FTTH",
    "place": {
      "id": "SU1CLzY1MDA0L1gvMDBINw",
      "href": "/geographicSite/SU1CLzY1MDA0L1gvMDBINw",
      "name": "IMB/65004/X/00H7",
      "isSiteInfoAvailable": true,
      "place": [
        {
          "geographicSubAddress": [
            {
              "internalBuildingReference": "SSS0100000000000198332600",
              "internalFloorReference": "",
              "buildingName": "_NA_",
              "levelNumber": "0",
              "levelType": "floor",
              "subUnit": [
                {
                  "subUnitNumber": "_NA_",
                  "subUnitType": "staircase",
                  "internalReference": "SSS0100000000000198332601",
                  "@type": "GeographicSubAddressUnitExtended",
                  "@baseType": "GeographicSubAddressUnit"
                }
              ],
              "@type": "GeographicSubAddressBuilding"
            }
          ],
          "@type": "GeographicAddress"
        }
      ],
      "relatedParty": [
        {
          "id": "FI",
          "@referredType": "OI"
        }
      ],
      "@type": "GeographicSiteBuilding",
      "@baseType": "GeographicSite"
    },
    "resourceStatus": "En service",
    "usageState": "Actif",
    "developerOutletReference": "",
    "toBeTicketed": false,
    "resourceRelationship": [
      {
        "id": "PT 000629",
        "relationshipType": "Connected PBO",
        "href": "/resource/pbo/UFQgMDAwNjI5QEZJLTY1MDU2LTAwMDM",
        "@referredType": "ResourcePbo"
      },
      {
        "id": "FI-65056-0003",
        "relationshipType": "Connected PM",
        "href": "/resource/pm/RkktNjUwNTYtMDAwMw",
        "@referredType": "ResourcePm"
      }
    ],
    "nonOapcInfo": {
      "startOperatingDate": "2023-04-01",
      "endOperatingDate": null,
      "predecessorIAR": ""
    },
    "hasFiberOpticDrawer": "",
    "description": "",
    "@baseType": "Resource",
    "@type": "ResourcePto",
    "FTTHLineStatus": [
      "existant",
      "actif",
      "raccordable",
      "commercialisable"
    ],
    "href": "/resource/pto/RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc"
  }

I need to find the values of several node in this structure. For this, I use the following function :

PropertyExists: function (obj, Field){
    var DataField = Field.split('.');

    if (DataField.length == 1){
        if (typeof obj === 'object' && obj !== null) {

            if (obj.hasOwnProperty(Field) && typeof obj[Field] === 'string') {              // if this object already contains the property, we are done
              return obj[Field].toLowerCase();
            }
            for (var p in obj) {                         // otherwise iterate on all the properties of this object.
                console.log(p)
                if ($S.PropertyExists(obj[p], Field)) { 
                    console.log(obj[p])
                    console.log(Field)
                    return obj[p][Field].toLowerCase(); // Error line
                }
            }
        }
        return false;
    } else {
        if (typeof obj === 'object' && obj !== null) {
            if (obj.hasOwnProperty(DataField[0]) && obj[DataField[0]].hasOwnProperty(DataField[1]) && typeof obj[DataField[0]][DataField[1]] === 'string') {
              return obj[DataField[0]][DataField[1]].toLowerCase();
            }
            for (var p in obj) {
                if ($S.PropertyExists(obj[p], Field)) { 
                    return obj[p][DataField[0]][DataField[1]].toLowerCase();
                }
            }
        }
        return false;
    }
}

When trying this code, the function works as expected :

console.log(PropertyExists(content, 'name'))

Outputs IMB/65004/X/00H7

But when trying this code, I get an error : obj[p][Field] is undefined at line // Error line

console.log(PropertyExists(content, 'buildingName'))

What I dont understand is that the console shows this, indicating that the node was found but when trying to return it id does not exist. The log also shows that before found the node is an object but after it is an array which must be the source of the problem.

enter image description here

Any hint appreciated, thx in advance !

2

Answers


  1. It is true that your code locates the string-typed property correctly, and then returns the corresponding value. But this happens at a deeper recursion level, and the caller of that recursive call ignores the value that is returned and instead expects to find the property at the current nesting level. This is wrong. If the property exists at level 3, then you shouldn’t be looking for it again, and certainly not at level 2.

    So just return what you received. Change this:

    if ($S.PropertyExists(obj[p], Field)) { 
        console.log(obj[p])
        console.log(Field)
        return obj[p][Field].toLowerCase(); // Error line
    }
    

    to this:

    const result = $S.PropertyExists(obj[p], Field);
    if (result !== false) {
        return result; // We already got the result, so just bubble it up.
    }
    

    On a final note: make sure to compare with false explicitly, because a found string property value could be the empty string, which is a falsy value. For that reason you should also change the following:

    if ($S.PropertyExists(obj[p], Field)) { 
    

    to:

    if ($S.PropertyExists(obj[p], Field) !== false) { 
    
    Login or Signup to reply.
  2. The issue with your JSON object and the function for accessing nested properties likely arise from how arrays are currently handled. Specifically, buildingName is nested within an array of objects.

    To fix this, modify your function to properly handle arrays when traversing the object. Below is an improved version of your PropertyExists function:

    function PropertyExists(obj, propertyPath) {
        if (!obj || typeof obj !== 'object') {
            return false;
        }
    
        const properties = propertyPath.split('.');
    
        let current = obj;
        for (const property of properties) {
            if (Array.isArray(current)) {
                const index = parseInt(property, 10);
                if (isNaN(index)) {
                    // If property is not a number, check all objects in the array
                    current = current.some(item => PropertyExists(item, properties.slice(properties.indexOf(property)).join('.')));
                    return current;
                } else {
                    // If property is a number, treat it as an array index
                    current = current[index];
                }
            } else {
                if (!current || !current.hasOwnProperty(property)) {
                    return false;
                }
                current = current[property];
            }
        }
    
        return true;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search