
The following two codes go through the whole object, an array of objects, or a collection of both to get the path to a particular key. There are two versions: first gets the path to the key only, and second gets the path where a key has the given value.
You can use
findPaths
method of the npm packagedeeply-nested for the same functionality.
A similar recursive solution as below can also be used to modify all the keys of a deeply nested object or array of objects.
1. Get Path to the Nested Key
Code
const findPath = (ob, key) => {
const path = [];
const keyExists = (obj) => {
if (
!obj ||
typeof key !== "string" ||
(typeof obj !== "object" && !Array.isArray(obj))
) {
return false;
} else if (obj.hasOwnProperty(key) && !Array.isArray(obj)) {
return true;
} else if (Array.isArray(obj)) {
let parentKey = path.length ? path.pop() : "";
for (let i = 0; i < obj.length; i++) {
path.push(`${parentKey}[${i}]`);
const result = keyExists(obj[i]);
if (result) {
return result;
}
path.pop();
}
} else {
for (const k in obj) {
path.push(k);
const result = keyExists(obj[k]);
if (result) {
return result;
}
path.pop();
}
}
return false;
};
keyExists(ob);
return path.join(".");
};
Examples
const deeplyNestedObj = {
a: {
b: {
c: {
d: {
e: "e",
f: "f",
g: {
G: undefined,
h: {
i: {},
j: {
k: {
K: null,
l: {
abc: 123,
},
},
},
},
},
},
},
},
},
e1: {},
f2: {},
P1: {
q1: {
r1: "r1",
},
},
};
console.log(findPath(deeplyNestedObj, "K")); // => a.b.c.d.g.h.j.k
console.log(findPath(deeplyNestedObj, "r1")); // => P1.q1
console.log(findPath(deeplyNestedObj, "gibberish")); // => ""
console.log(findPath(deeplyNestedObj, "helloWorld")); // => ""
Use Case
Compare a known path for an object in a single check without needing multiple &&
comparisons or a try-catch block. Example:
const errorResponse = {
status: 403,
data: {
user: {
errorMessage: "You're not authorized to update this user.",
},
},
};
if (findPath(errorResponse, "errorMessage") === "data.user") {
// true
//...
}
2. Get Path to the Nested Key With Given Value
With slight modification, we can make the above code compare the value given for the key.
const findPath = (ob, key, value) => {
const path = [];
const keyExists = (obj) => {
if (
!obj ||
typeof key !== "string" ||
(typeof obj !== "object" && !Array.isArray(obj))
) {
return false;
} else if (obj.hasOwnProperty(key) && && !Array.isArray(obj) && obj[key] === value) {
return true;
} else if (Array.isArray(obj)) {
let parentKey = path.length ? path.pop() : "";
for (let i = 0; i < obj.length; i++) {
path.push(`${parentKey}[${i}]`);
const result = keyExists(obj[i]);
if (result) {
return result;
}
path.pop();
}
} else {
for (const k in obj) {
path.push(k);
const result = keyExists(obj[k]);
if (result) {
return result;
}
path.pop();
}
}
return false;
};
keyExists(ob);
return path.join(".");
};
const deeplyNestedFamilyTree = [
// starts with array
{
name: "John",
children: [
{
name: "Dora",
children: [
{
name: "Sara",
},
{
name: "James",
},
],
},
],
},
{
name: "Scott",
children: [
{
name: "Smith",
children: [
{
name: "Brad",
},
{
name: "David",
},
],
},
],
},
];
const deeplyNestedOrgChart = {
// starts with object
position: "CEO",
subordinates: [
{
position: "CFO",
},
{
position: "CTO",
subordinates: [
{
position: "Engineering Lead",
},
],
},
{
position: "COO",
},
],
};
console.log(findPath(deeplyNestedFamilyTree, "name", "John"));
// => [0]
console.log(findPath(deeplyNestedFamilyTree, "name", "James"));
// => [0].children[0].children[1]
console.log(findPath(deeplyNestedFamilyTree, "name", "Scott"));
// => [1]
console.log(findPath(deeplyNestedOrgChart, "position", "Engineering Lead"));
// => subordinates[1].subordinates[0]
Limitation
The limitation of the above codes is that they only return the first path found for a given key or key/value pair.
See also
- Python Check if Key Exists in Deeply Nested Dictionary or List of Dictionaries, Without Knowing the Path
- SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
- Yup Date Format Validation With Moment JS
- Yup Number Validation: Allow Empty String
- Exactly Same Query Behaving Differently in Mongo Client and Mongoose
- JavaScript Unit Testing JSON Schema Validation
- Reduce JS Size With Constant Strings