Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

159
Views
Find path to ALL matching key values in nested object

I have a function that gets me the path to the first finding of a nested object where the key and the value matches.

function getPath(obj, givenKey, givenValue) {
    for(var key in obj) {                                   
        if(obj[key] && typeof obj[key] === "object") {      
            var result = getPath(obj[key], givenValue, givenKey);
            if(result) {                                    
                result.unshift(key)
                return result;                              
            }
        } else if(obj[key] === givenValue && key === givenKey ) {
            return [key];
        }   
    }
}

sample data

var myObj = [
{
    "name": "needle",
    "children": [
    {
        "name": "group2",
        "children": [
        {
            "name": "item0"
        }]
    }]
},
{
    "name": "item1"
},
{
    "name": "needleGroup",
    "children": [
    {
        "name": "needleNestedGroup",
        "children": [
        {
            "name": "item3"
        },
        {
            "name": "needleNestedDeeperGroup",
            "children": [
            {
                "name": "needle"
            }]
        }]
    }]
}];

expected output

getPath(myObj, "name", "needle"):
      [0, "name"]
      ["2","children","0","children","1","children","0","name"]

However, I have now an object that contains these key-values multiple times, so I have multiple matches.

How can I get all of them in an array? My current function is just stopping after it finds the first match. The fact, that it's recursive makes things very complicated for me

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

I would write this atop a more generic findAllPaths function that accepts a predicate and finds the paths of all nodes in the object that match that predicate. With that, then findPathsByName is as simple as (target) => findAllPaths (({name}) => name == target).

In turn, I build findAllPaths on pathEntries, variants of which I use all the time. This function turns an object into an array of path/value pairs. Some versions only generate the leaf nodes. This one generate it for all nodes, including the root (with an empty path.) The basic idea of this function is to turn something like:

{a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}

into this:

[
  [[], {a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}], 
  [['a'], 'foo'], 
  [['b'], {c: ['bar', 'baz'], f: 'qux'}], 
  [['b', 'c'], ['bar', 'baz']], 
  [['b', 'c', 0], 'bar'], 
  [['b', 'c', 1], 'baz'], 
  [['b', 'f'], 'qux']
]

where the first item in every subarray is a path and the second a reference to the value at that path.

Here is what it might look like:

const pathEntries = (obj) => [
  [[], obj],
  ...Object (obj) === obj
    ? Object .entries (obj) .flatMap (
        ([k, x]) => pathEntries (x) .map (
          ([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
        )
      )
    : []
]

const findAllPaths = (predicate) => (o) =>
  [...pathEntries (o)] .filter (([p, v]) => predicate (v, p)) .map (([p]) => p)

const findPathsByName = (target) => findAllPaths (({name}) => name == target)

const myObj = [{name: "needle", children: [{name: "group2", children: [{name: "item0"}]}]}, {name: "item1"}, {name: "needleGroup", children: [{name: "needleNestedGroup", children: [{name: "item3"}, {name: "needleNestedDeeperGroup", children: [{name: "needle"}]}]}]}]

console .log (findPathsByName ('needle') (myObj))
.as-console-wrapper {max-height: 100% !important; top: 0}

The question asked for string values for the array indices. I prefer the integer values myself as done here, but you simplify the function a bit:

-          ([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
+          ([p, v]) => [[k, ... p], v]
about 4 years ago · Juan Pablo Isaza Report

0

Instead of returning the value, you could push it to an array and keep iterating.

At the end of the function, you return the array.

function getPath(obj, givenKey, givenValue) {
  let matches = [];
  for (var key in obj) {
    if (obj[key] && typeof obj[key] === "object") {
      var result = getPath(obj[key], givenValue, givenKey);
      if (result) {
        result.unshift(key)
        matches.push(...result);
      }
    } else if (obj[key] === givenValue && key === givenKey) {
      matches.push(key);
    }
  }
  
  return matches;
}

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!