DEV Community

Discussion on: Search through a JSON object using JavaScript

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Finally, at the cost of a tiny bit of memory, you can keep a Set of visited objects so you can prevent infinite recursion without a counter.

Before:

const obj = {
  a: 0,
  b: 1,
  c: [[]]
}
const obj2 = {t:obj}
obj.c[0].push(obj2, 't')
console.log(findPaths(obj,"t"));
[ 'c/0/0/t',
  'c/0/0/t/c/0/0/t',
  'c/0/0/t/c/0/0/t/c/0/0/t',
  'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t',
  'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t',
  'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t/c/0/1',
  'c/0/0/t/c/0/0/t/c/0/0/t/c/0/1',
  'c/0/0/t/c/0/0/t/c/0/1',
  'c/0/0/t/c/0/1',
  'c/0/1' ]

After:

Output:

[ 'c/0/0/t', 'c/0/1' ]

Code:

/**
 * searches deep into an object recursively...
 * @param {Object} obj object to be searched
 * @param {any} searchValue the value/key to search for
 * @param {boolean} [searchKeys] whether to search object keys as well as values. Defaults to `true` if `serchValue` is a string, `false` otherwise.
 * @returns {string[]} Paths on the object to the matching results
 */
const findPaths = (
  obj,
  searchValue,
  searchKeys = typeof searchValue === "string"
) => {
  const paths = []
  const visited = new Set()
  const notObject = typeof searchValue !== "object"
  const gvpio = (obj, prefix) => {
    for (const [curr, currElem] of Object.entries(obj)) {
      if (searchKeys && curr === searchValue) {
        paths.push(prefix + curr)
      }

      if (typeof currElem === "object") {
        if (visited.has(currElem)) continue
        visited.add(currElem)
        gvpio(currElem, prefix + curr + "/")
        if (notObject) continue
      }
      if (currElem === searchValue) {
        paths.push(prefix + curr)
      }
    }
  }
  gvpio(obj, "")
  return paths
}

Disclaimer:

Be careful though, it won't always include the shortest path!

const obj = {
  t: "t"
}
const obj2 = {
  a: [{ a: [{ a: [{ obj }] }] }],
  b: obj
}
console.log(findPaths(obj2, "t"));
[ 'a/0/a/0/a/0/obj/t', 'a/0/a/0/a/0/obj/t' ] // :(