JavaScript Check if Key Exists in Deeply Nested Object or Array of Objects, Without Knowing the Path

Depth First Search (DFS) for key verification in an object

The following JavaScript code recursively goes through the whole object, array of objects or a collection of both to verify if the given key exists somewhere down the object. It does not require path to the key in advance.

Code

const keyExists = (obj, key) => {
  if (!obj || (typeof obj !== "object" && !Array.isArray(obj))) {
    return false;
  }
  else if (obj.hasOwnProperty(key)) {
    return true;
  }
  else if (Array.isArray(obj)) {
    for (let i = 0; i < obj.length; i++) {
      const result = keyExists(obj[i], key);
      if (result) {
        return result;
      }
    }
  }
  else {
    for (const k in obj) {
      const result = keyExists(obj[k], key);
      if (result) {
        return result;
      }
    }
  }

  return false;
};

Example

const deeplyNestedObj = {
  a: {
    b: {
      c: {
        d: {
          e: "e",
          f: "f",
          g: {
            G: undefined,
            h: {
              i: {},
              j: {
                k: {
                  K: null,
                  l: {
                    abc: 123,
                    m: {
                      n: {
                        o: {
                          p: {
                            q: "q",
                            r: "r",
                            s: "s",
                            u: "u",
                            gibberishObjects: [
                              { gibberishId: 1 },
                              { gibberishId: 2 },
                              "Gibberish String",
                              null],
                            aFunction: () => {
                              return true;
                            },
                            anotherDeepObject: {
                              randomDates: {
                                "1999-06-06": {
                                  users: 100
                                },
                                "2021-jun": "Euro Cup"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  e1: {},
  f2: {},
  P1: {
    q1: {
      r1: "r1"
    }
  }
}


console.log(keyExists(deeplyNestedObj, "2021-jun")) //true
console.log(keyExists(deeplyNestedObj, "e1")) //true
console.log(keyExists(deeplyNestedObj, "r3")) //false
console.log(keyExists(deeplyNestedObj, "xyz")) //false
console.log(keyExists(deeplyNestedObj, "gibberishId")) //true

Use

Although most of the times we’re aware of the path we need to check for a given key, this method can be used where we’re only interested in the existence of a key. This might be because of the badly-formed JSON structure, or a particular API response. Consider the following example:

  const yearlyReport = {
    q1: {
      jan: {
        risk: {
          //...
        }
      },
      feb: {

      },
      mar: {

      }
    },
    q2: {
      apr: {

      },
      may: {

      },
      jun: {

      }
    },
    q3: {
      jul: {

      },
      aug: {

      },
      sep: {
        bonuses: [
          //...
        ]
      }
    },
    q4: {
      oct: {

      },
      nov: {
        risk: true
      },
      dec: {

      }
    }
  }
  
  
  console.log(keyExists(yearlyReport, "risk")); // true
  console.log(keyExists(yearlyReport, "bonuses")); // true
  console.log(keyExists(yearlyReport, "holidays")); // false

Here we might only be interested in knowing if the risk, bonuses or holidays key exists somewhere deep down the object, no matter in which quarter or which month (assuming their existence means something to us, without knowing their values). For example, we might show on a calendar, without marking the exact quarter and month, that a selected year has planned bonuses, but no holidays, and there’s some risk.

Here’s another example:

  const serverResponse = {
    data: {
      availableBookings: {
        hallA: {
          "2021-07-01": true,
          "2021-07-02": true,
          "2021-07-03": true,
          "2021-07-05": true,
          "2021-08-06": true,
          "2021-08-07": true,
          "2021-08-08": {
            //...
          }
        },
        hallB: {
          "2021-07-20": true,
          "2021-07-05": {
            //...
          }
        },
        hallC: {
          section1: {
            "2021-07-02": true,
            "2021-07-15": true
          },
          section2: {
            "2021-07-22": true,
            "2021-07-25": true
          },
          section3: {
            "2021-07-12": true,
            "2021-07-18": true
          }
        }
      }
    }
  }

  console.log(keyExists(serverResponse, "2021-07-02")); // true
  console.log(keyExists(serverResponse, "2021-07-15")); // true
  console.log(keyExists(serverResponse, "2021-08-15")); // false
  console.log(keyExists(serverResponse, "2021-09-15")); // false
  console.log(keyExists(serverResponse, "2021-10-15")); // false

Let’s say the presence of date key in a hall or sections means it’s available for booking (irrespective of its value). We’re not interested in knowing which hall or section has the availability. We can find the booking availability for a particular date across the halls and sections.

See also