javascriptarraysobjectiteration

Javascript : Find node value through recursive iteration


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 !


Solution

  • 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) {