skip to Main Content

For a simple object:

const simpleObject = {
    "a": "aaa" ,
    "b": "bbb" ,
};

I know how to get the key of a value:

Object.keys(simpleObject).find(key => simpleObject[key] === "aaa");

However, if I have a complex object like this:

const complexObject = {
    "A": [  "a1", {"a2": ["a21", "a22" ]}, "a3"],   //compact representation
    "B": [                                          //expanded representation
            "b1", 
            "b2",
            {"b3": [
                    "b31", 
                    "b32"
                ]
            }
         ],
};

How to return the key of a value as deep as possible? For example:

Input Output
A A
a1 A
a2 A
a21 A.a2

I think the first step is to get the value list of all the keys:

valueList = Object.values(map1);

then using some kind of loop. But I don’t know how to work it out.

In best scenario the pattern of the object can be go on, but if that’s too hard then stopping the recursion at level 2 is fine.

I need a solution that works on plain JS (I’m making an automation script for Fibery). But if there is a framework I’m happy to know.

2

Answers


  1. This can be solved by recursively searching for the value in an object.

    Below is an example for it. (assuming non-null values)

    const complexObject={A:["a1",{a2:["a21","a22"]},"a3"],B:["b1","b2",{b3:["b31","b32"]}]};
    
    function findValue(obj, value, path = "") {
    
        /** Traverse through the object or array. */
        for (const key in obj) {
            const val = obj[key];
            
            /** If key itself the value, then stop it. */
            if (key === value) {
              return (path !== "") ? path + "." + key : key;
            }
            
            /** If it's a string, then it's a dead end. */
            if ((typeof val === "string")) {
                if (val === value) {
                    return (path !== "") ? path + "." + key : key;
                }
            } else {
    
                /** If it's not, then we need to traverse again. */
                const newPath = (path !== "") ? path + "." + key : key;
                const val = findValue(obj[key], value, newPath);
                if (val !== null) {
                    return val;
                }
            }
        }
    
        return null;
    }
    
    const query = prompt("What value you want to find?", "a21");
    const answer = findValue(complexObject, query);
    
    document.write(answer);
    Login or Signup to reply.
  2. You could build the path when unwinding from recursion. The base case is when either the given object is the value itself, or the (non-array) object has the value as its key.

    function findValue(obj, value) {
        if (Object(obj) !== obj) return obj === value ? "." : "";
        if (!Array.isArray(obj) && Object.hasOwn(obj, value)) return ".";
        for (const [key, child] of Object.entries(obj)) {
            const path = findValue(child, value);
            if (path) return Array.isArray(obj) ? path : (key + "." + path).replace(/.+$/, "");
        }
    }
    
    // The example from the question:
    const complexObject = {A:["a1",{a2:["a21","a22"]},"a3"],B:["b1","b2",{b3:["b31","b32"]}]};
    console.log(findValue(complexObject, "a1")); // A
    console.log(findValue(complexObject, "a2")); // A
    console.log(findValue(complexObject, "a21")); // A.a2

    Note that to be in line with your expected output, this output has no indication about the index of the array where the value was found; it just lists the keys of plain objects.

    Also, if the value happens to be a key of the top-level object, then there is no path to output. In that case this solution outputs "." so to still have a clue that the value was found.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search