Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

165
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda