Js как найти элемент в json

I had a JSON string / object in my application.

{"list": [
    {"name":"my Name","id":12,"type":"car owner"},
    {"name":"my Name2","id":13,"type":"car owner2"},
    {"name":"my Name4","id":14,"type":"car owner3"},
    {"name":"my Name4","id":15,"type":"car owner5"}
]}

I had a filter box in my application, and when I type a name into that box, we have to filter the object and display the result.

For example, if the user types «name» and hits search, then we have to search full names in the JSON object and return the array, just like a MySQL search …

My question is to filter the json object with string and return the array….

asked May 21, 2012 at 4:42

ramesh's user avatar

rameshramesh

3,97813 gold badges71 silver badges117 bronze badges

5

You could just loop through the array and find the matches:

var results = [];
var searchField = "name";
var searchVal = "my Name";
for (var i=0 ; i < obj.list.length ; i++)
{
    if (obj.list[i][searchField] == searchVal) {
        results.push(obj.list[i]);
    }
}

answered May 21, 2012 at 4:49

McGarnagle's user avatar

McGarnagleMcGarnagle

101k31 gold badges228 silver badges260 bronze badges

0

If your question is, is there some built-in thing that will do the search for you, then no, there isn’t. You basically loop through the array using either String#indexOf or a regular expression to test the strings.

For the loop, you have at least three choices:

  1. A boring old for loop.

  2. On ES5-enabled environments (or with a shim), Array#filter.

  3. Because you’re using jQuery, jQuery.map.

Boring old for loop example:

function search(source, name) {
    var results = [];
    var index;
    var entry;

    name = name.toUpperCase();
    for (index = 0; index < source.length; ++index) {
        entry = source[index];
        if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
            results.push(entry);
        }
    }

    return results;
}

Where you’d call that with obj.list as source and the desired name fragment as name.

Or if there’s any chance there are blank entries or entries without names, change the if to:

        if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {

Array#filter example:

function search(source, name) {
    var results;

    name = name.toUpperCase();
    results = source.filter(function(entry) {
        return entry.name.toUpperCase().indexOf(name) !== -1;
    });
    return results;
}

And again, if any chance that there are blank entries (e.g., undefined, as opposed to missing; filter will skip missing entries), change the inner return to:

        return entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1;

jQuery.map example (here I’m assuming jQuery = $ as is usually the case; change $ to jQuery if you’re using noConflict):

function search(source, name) {
    var results;

    name = name.toUpperCase();
    results = $.map(source, function(entry) {
        var match = entry.name.toUpperCase().indexOf(name) !== -1;
        return match ? entry : null;
    });
    return results;
}

(And again, add entry && entry.name && in there if necessary.)

answered May 21, 2012 at 4:48

T.J. Crowder's user avatar

T.J. CrowderT.J. Crowder

1.0m187 gold badges1908 silver badges1862 bronze badges

6

You can simply save your data in a variable and use find(to get single object of records) or filter(to get single array of records) method of JavaScript.

For example :-

let data = {
 "list": [
   {"name":"my Name","id":12,"type":"car owner"},
   {"name":"my Name2","id":13,"type":"car owner2"},
   {"name":"my Name4","id":14,"type":"car owner3"},
   {"name":"my Name4","id":15,"type":"car owner5"}
]}

and now use below command onkeyup or enter

to get single object

data.list.find( record => record.name === "my Name")

to get single array object

data.list.filter( record => record.name === "my Name")

Ejaz47's user avatar

Ejaz47

1451 silver badge12 bronze badges

answered Feb 5, 2020 at 4:15

Anand Deep Singh's user avatar

Anand Deep SinghAnand Deep Singh

2,5173 gold badges22 silver badges28 bronze badges

Use PaulGuo’s jSQL, a SQL like database using javascript. For example:

var db = new jSQL();
db.create('dbname', testListData).use('dbname');
var data = db.select('*').where(function(o) {
    return o.name == 'Jacking';
}).listAll();

answered May 21, 2012 at 5:12

JackingLiu's user avatar

I adapted regex to work with JSON.

First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:

"matched".search("ch") // yields 3

For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I’d recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).

Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:

find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain

With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.

You can see the library and code I authored at http://json.spiritway.co/

answered Mar 27, 2015 at 19:36

mikewhit's user avatar

1

If you are doing this in more than one place in your application it would make sense to use a client-side JSON database because creating custom search functions that get called by array.filter() is messy and less maintainable than the alternative.

Check out ForerunnerDB which provides you with a very powerful client-side JSON database system and includes a very simple query language to help you do exactly what you are looking for:

// Create a new instance of ForerunnerDB and then ask for a database
var fdb = new ForerunnerDB(),
    db = fdb.db('myTestDatabase'),
    coll;

// Create our new collection (like a MySQL table) and change the default
// primary key from "_id" to "id"
coll = db.collection('myCollection', {primaryKey: 'id'});

// Insert our records into the collection
coll.insert([
    {"name":"my Name","id":12,"type":"car owner"},
    {"name":"my Name2","id":13,"type":"car owner2"},
    {"name":"my Name4","id":14,"type":"car owner3"},
    {"name":"my Name4","id":15,"type":"car owner5"}
]);

// Search the collection for the string "my nam" as a case insensitive
// regular expression - this search will match all records because every
// name field has the text "my Nam" in it
var searchResultArray = coll.find({
    name: /my nam/i
});

console.log(searchResultArray);

/* Outputs
[
    {"name":"my Name","id":12,"type":"car owner"},
    {"name":"my Name2","id":13,"type":"car owner2"},
    {"name":"my Name4","id":14,"type":"car owner3"},
    {"name":"my Name4","id":15,"type":"car owner5"}
]
*/

Disclaimer: I am the developer of ForerunnerDB.

answered Dec 7, 2016 at 15:34

Rob Evans's user avatar

Rob EvansRob Evans

6,7404 gold badges38 silver badges56 bronze badges

0

Here is an iterative solution using object-scan. The advantage is that you can easily do other processing in the filter function and specify the paths in a more readable format. There is a trade-off in introducing a dependency though, so it really depends on your use case.

// const objectScan = require('object-scan');

const search = (haystack, k, v) => objectScan([`list[*].${k}`], {
  rtn: 'parent',
  filterFn: ({ value }) => value === v
})(haystack);

const obj = { list: [ { name: 'my Name', id: 12, type: 'car owner' }, { name: 'my Name2', id: 13, type: 'car owner2' }, { name: 'my Name4', id: 14, type: 'car owner3' }, { name: 'my Name4', id: 15, type: 'car owner5' } ] };

console.log(search(obj, 'name', 'my Name'));
// => [ { name: 'my Name', id: 12, type: 'car owner' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer: I’m the author of object-scan

answered Nov 18, 2020 at 5:58

vincent's user avatar

vincentvincent

1,8833 gold badges17 silver badges24 bronze badges

You can filter json object using any value from any property using this library
Js-Search

answered Jun 3, 2022 at 19:58

Cyber Progs's user avatar

Cyber ProgsCyber Progs

3,5963 gold badges29 silver badges39 bronze badges

You can try this:

function search(data,search) {
    var obj = [], index=0;
    for(var i=0; i<data.length; i++) {
      for(key in data[i]){
         if(data[i][key].toString().toLowerCase().indexOf(search.toLowerCase())!=-1) {
                obj[index] = data[i];
                index++;
                break;
         }
     }
     return obj;
}
console.log(search(obj.list,'my Name'));

bfontaine's user avatar

bfontaine

17.8k13 gold badges71 silver badges103 bronze badges

answered Oct 19, 2017 at 9:20

Mengty's user avatar

0

Я хочу сделать проверку файла JSON, там найти строку «nick» у всех пользователей, и сделать так:
(if(nick = "хай") return)
то есть, если у кого-то из участников nick = хай, то ничего не выполнялось, как из всего JSON найти значение nick = хай, или можно сделать проще?
Вот мой JSON:

{
		"id": 124124,
		"firstname": "Районный",
		"lastname": "Прокурор",
		"warns": 0,
		"role": 11,
		"flip": 0,
		"rank": "Участник",
		"ban": false,
		"isBanned": "Нет",
		"tempban": 0,
		"mute": 0,
		"mutesleft": 0,
		"violations": 0,
		"botmute": 0,
		"nick": "хай"
	},
	{
		"id": 123123,
		"firstname": "Кто",
		"lastname": "Никто",
		"warns": 0,
		"role": 11,
		"flip": 0,
		"rank": "Участник",
		"ban": false,
		"isBanned": "Нет",
		"tempban": 0,
		"mute": 0,
		"mutesleft": 0,
		"violations": 0,
		"botmute": 0
		"nick": "пока"
	},
	{
		"id": 125125,
		"firstname": "Крутой",
		"lastname": "Поц",
		"warns": 0,
		"role": 1,
		"flip": 0,
		"rank": "Участник",
		"ban": false,
		"isBanned": "Нет",
		"tempban": 0,
		"mute": 0,
		"mutesleft": 0,
		"violations": 0
		"nick": "привет"
	}

I cant find one way to get this value («comment») into json using javascript.

var myJSONObject = {
    "topicos": [{
        "comment": {
            "commentable_type": "Topico", 
            "updated_at": "2009-06-21T18:30:31Z", 
            "body": "Claro, Fernando! Eu acho isso um extremo desrespeito. Com os celulares de hoje que atu00e9 filmam, poderu00edamos achar um jeito de ter postos de denu00fancia que receberiam esses vu00eddeos e recolheriam os motoristas paressadinhos para um treinamento. O que vocu00ea acha?", 
            "lft": 1, 
            "id": 187, 
            "commentable_id": 94, 
            "user_id": 9, 
            "tipo": "ideia", 
            "rgt": 2, 
            "parent_id": null, 
            "created_at": "2009-06-21T18:30:31Z"
        }
    }]
};

I’m trying a example like this:

alert(myJSONObject.topicos[0].data[0]);

Some body can help me?

The json is from Ruby On rails application, using render :json => @atividades.to_json

Tks a lot!
Marqueti

Introduction

Recursive search is a technique for traversing a data structure and searching for an element or elements that match a specific condition. In JavaScript, this can be particularly useful when working with complex data structures such as JSON objects.

One common use case for a recursive search in a JSON object is to find a value by its key or to find all values that match a certain condition.

In this article, we will discuss how to carry out recursive search in JSON objects.

Recursive search in JSON object

To illustrate how we can achieve recursive search in JSON objects, we will need to work with some examples.

For example, consider a JSON object representing a list of employees in an organization, with nested objects for each employee’s personal and professional information. If we wanted to find the email address of a specific employee, we could use a recursive search function to iterate through the object and return the value of the "email" key for the matching employee.

ALSO READ: JavaScript Math.fround() Examples [In-Depth Tutorial]

To implement a recursive search in a JSON object in JavaScript, we can use a function that takes three arguments: the object to search, the key or condition we want to match, and an optional results array to store the matching values. The function should first check if the object is a primitive value (such as a string, number, or boolean); if it is, it should return the value if it matches the key or condition, or undefined otherwise. If the object is not a primitive value, the function should iterate over the object’s properties and call itself recursively on each property.

Example-1: Find specific value in JSON Object

Here is an example of a recursive search function that finds the value of a specific key in a JSON object:

function search(obj, key) {
    if (typeof obj !== "object" || obj === null) {
        return obj === key ? obj : undefined;
    }
    for (const [k, v] of Object.entries(obj)) {
        const result = search(v, key);
        if (result !== undefined) {
            return result;
        }
    }
    return undefined;
}

This function works by using the typeof operator to check if the input obj is an object. If it is not, it checks if the value is equal to the key using the strict equality operator (===) and returns the value if it is, or undefined otherwise. If the obj is an object, it uses the Object.entries method to iterate over the object’s properties and calls itself recursively on each property using the search function itself. If the recursive call returns a value other than undefined, the value is returned; otherwise, the loop continues until all properties have been searched.

To use this function, we can pass in a JSON object and the key we want to find:

const employees = {
    Abhi: {
        name: "Abhi",
        email: "abhi@example.com",
        title: "Manager",
        department: "Marketing",
    },
    Anurag: {
        name: "Anurag",
        email: "anurag@example.com",
        title: "Developer",
        department: "Engineering",
    },
    Vishal: {
        name: "Vishal",
        email: "vishal@example.com",
        title: "Manager",
        department: "Marketing",
    },
    Saurav: {
        name: "Saurav",
        email: "saurav@example.com",
        title: "Designer",
        department: "Design",
    },
};

const AbhiEmail = search(employees, "abhi@example.com");
console.log(AbhiEmail);

Output

abhi@example.com

This function can be useful for finding a specific value in a complex JSON object, such as a particular employee’s email address in the example above.

ALSO READ: How to use JavaScript Math.random() Method? [SOLVED]

We can also modify the function to search for values that match a certain condition rather than a specific key. For example, we might want to find all employees who have the title of «Manager». To do this, we can modify the function to accept a condition function as the second argument, which should return a boolean value indicating whether the value matches the condition.

Example-2: Find all values based on condition match

Here is an example of a recursive search function that finds all values that match a condition in a JSON object

function search(obj, fn, results = []) {
    if (typeof obj !== "object" || obj === null) {
        if (fn(obj)) {
            results.push(obj);
        }
        return results;
    }
    for (const [k, v] of Object.entries(obj)) {
        search(v, fn, results);
    }
    return results;
}

This function works similarly to the previous version, but instead of returning the first matching value it encounters, it pushes all matching values to the results array and returns the array at the end. To use this function, we can pass in a JSON object and a condition function that checks for the desired value:

const managers = search(employees, (value) => value === "Manager");
console.log(managers);

Output

[ 'Manager', 'Manager' ]

In this example, the condition function uses the strict equality operator (===) to check if the value is equal to «Manager». If it is, the value is added to the results array.

ALSO READ: Cannot set headers after they are sent to client [SOLVED]

Example-3: Creating a recursive search function

We can use a recursive function to search through a JSON object in JavaScript. The function should take in the current object, the key we are searching for, and the value we are searching for as parameters. Inside the function, we can use a for loop to iterate through the object’s keys. If the current key matches the search key and the corresponding value matches the search value, we can return the current object. If the current value is an object, we can call the function recursively with the current value as the new object to search.

Here is an example of a recursive function that searches for a key-value pair in a JSON object. We will re-use our JSON object from previous example:

function searchJSON(obj, key, val) {
  let results = [];
  for (let k in obj) {
    if (obj.hasOwnProperty(k)) {
      if (k === key && obj[k] === val) {
        results.push(obj);
      } else if (typeof obj[k] === "object") {
        results = results.concat(searchJSON(obj[k], key, val));
      }
    }
  }
  return results;
}

let employeed = {...}; // your JSON object
let key = "name";
let val = "Ramesh";
let results = searchJSON(json, key, val);
console.log(results);

Output:

[
  {
    name: 'Anurag',
    email: 'anurag@example.com',
    title: 'Developer',
    department: 'Engineering'
  }
]

Example-4: Using Array.prototype.filter() method

The filter() method from Array.prototype.filter() creates a new array with all elements that pass the test implemented by the provided function. Here’s an example of how we can use the filter() method to search for a key-value pair in a JSON object:

let json = {
  "person1": {
    "name": "Rahul",
    "age": 25
  },
  "person2": {
    "name": "Amrit",
    "age": 30
  },
  "person3": {
    "name": "Ravi",
    "age": 35
  }
}

let key = "name";
let val = "Rahul";
let results = Object.values(json).filter(person => person[key] === val);
console.log(results);

Output:

[ { name: 'Rahul', age: 25 } ]

ALSO READ: 4 Efficient Ways to validate Email Address in JavaScript

Example-5: Using Object.entries and Array.prototype.filter()

Here we will use Object.entries along with Array.prototype.filter() to perform a recursive search through the JSON object:

let json = {
  "person1": {
    "name": "Rahul",
    "age": 25
  },
  "person2": {
    "name": "Amit",
    "age": 30
  },
  "person3": {
    "name": "Rekha",
    "age": 35
  }
}

let key = "name";
let val = "Rahul";
let results = Object.entries(json).filter(entry => entry[1][key] === val).map(entry=>entry[1]);
console.log(results);

Output

[ { name: 'Rahul', age: 25 } ]

Example-6: Using Array.prototype.reduce()

We can also use the reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.

let json = {
  "person1": {
    "name": "Rahul",
    "age": 25
  },
  "person2": {
    "name": "Amit",
    "age": 30
  },
  "person3": {
    "name": "Rahul",
    "age": 35
  }
}

let key = "name";
let val = "Rahul";
let results = Object.values(json).reduce((acc, curr) => {
  if(curr[key] === val) {
    acc.push(curr);
  }
  return acc;
}, []);
console.log(results);

Output

[ { name: 'Rahul', age: 25 }, { name: 'Rahul', age: 35 } ]

Example-7: Perform a regex search inside JSON Object recursively

Instead of checking for an exact match of the key-value pair, we can use the RegExp.prototype.test() method to check if the value matches the regular expression. Here’s an update code which we used in previous example:

let json = {
  "person1": {
    "name": "Rahul",
    "age": 25
  },
  "person2": {
    "name": "Amit",
    "age": 30
  },
  "person3": {
    "name": "Ram",
    "age": 35
  }
}

let key = "name";
let val = /^Ra/; // regular expression
let results = Object.values(json).filter(person => val.test(person[key]));
console.log(results);

This will return an array containing the objects that have a key «name» with a value that starts with «Ra«.

ALSO READ: JavaScript convert String To Array [4 Methods]

Output:

[ { name: 'Rahul', age: 25 }, { name: 'Ram', age: 35 } ]

Summary

Recursive search is a powerful technique for traversing and searching complex data structures in JavaScript, such as JSON objects. By using a recursive search function, developers can easily find specific values or all values that match a certain condition within a JSON object.

In summary, recursive search is a technique for traversing a data structure and searching for an element or elements that match a specific condition. In JavaScript, this can be particularly useful when working with complex data structures such as JSON objects. By using a recursive search function, developers can easily find specific values or all values that match a certain condition within a JSON object.

References

JSON — JavaScript | MDN (mozilla.org)
Recursion — MDN Web Docs Glossary: Definitions of Web-related terms | MDN (mozilla.org)

Cover image for Search through a JSON object using JavaScript

As my opening contribution, i leave here a method i developed to search inside a JSON object for a specific value (could be or not the name of the object property).

https://gist.github.com/killants/569c4af5f2983e340512916e15a48ac0

I’ll be happy if at least one person finds it usefull.

Feel free to edit and improve it! Any feedback is welcome!

Top comments (13)


Collapse

Expand


qm3ster profile image

Without changing the structure, I would do the following:

const charSeparator = "/"
/**
 * searches deep into an object recursively...
 * @param {Object} obj object to be searched
 * @param {any} searchValue the value/key to search for
 * @param {boolean} [valuesOnly=false] whether to skip comparing object keys
 * @param {number} [maxDepth=20] maximum recursion depth (to avoid "Maximum call stack size exceeded")
 * @returns {string[]} Paths on the object to the matching results
 */
function getValuePathInObject(
  obj,
  searchValue,
  valuesOnly = false,
  maxDepth = 20
) {
  if (!maxDepth) return []

  const paths = []

  for (const [curr, currElem] of Object.entries(obj)) {

    if (!valuesOnly && curr === searchValue) {
      // To search for property name too...
      paths.push(curr)
    }

    if (typeof currElem == "object") {
      // object is "object" and "array" is also in the eyes of `typeof`
      // search again :D
      const deepPaths = getValuePathInObject(
        currElem,
        searchValue,
        valuesOnly,
        maxDepth - 1
      )
      const currDir = curr + charSeparator
      for (const path of deepPaths) {
        paths.push(currDir + path)
      }
      continue
    }
    // it's something else... probably the value we are looking for
    // compares with `searchValue`
    if (currElem === searchValue) {
      // return index AND/OR property name
      paths.push(curr)
    }
  }
  return paths
}
  1. Use const and let, never var.
  2. Use for of loops instead of imperative key and numeric index iteration.
  3. Remove the debug logging
  4. Hoist the constant charSeparator out of the function (or you could inline the "/" literal)
  5. Only concatenate curr and charSeparator once, not in the loop.
  6. Remove unused variable i.
  7. Use early return (or rather, continue).
  8. Use JSDoc, LMAO xD
  9. Use down-counting depth limit to pass only one number.
  10. Use defaults in the function parameters. These only check for undefined, not truthiness, so passing false and 0 won’t trigger them.


Collapse

Expand


qm3ster profile image

Otherwise, I’d use an inner recursive function so that I can do option parsing once, and then close over one array I will always append to, to avoid allocating intermediate arrays:

/**
 * searches deep into an object recursively...
 * @param {Object} obj object to be searched
 * @param {any} searchValue the value/key to search for
 * @param {Object} [options]
 * @param {boolean} options.[searchKeys] whether to search object keys as well as values. Defaults to `true` if `serchValue` is a string, `false` otherwise.
 * @param {number} options.[maxDepth=20] maximum recursion depth (to avoid "Maximum call stack size exceeded")
 * @returns {string[]} Paths on the object to the matching results
 */
const findPaths = (
  obj,
  searchValue,
  { searchKeys = typeof searchValue === "string", maxDepth = 20 } = {}
) => {
  const paths = []
  const notObject = typeof searchValue !== "object"
  const gvpio = (obj, maxDepth, prefix) => {
    if (!maxDepth) return

    for (const [curr, currElem] of Object.entries(obj)) {
      if (searchKeys && curr === searchValue) {
        // To search for property name too ...
        paths.push(prefix + curr)
      }

      if (typeof currElem === "object") {
        // object is "object" and "array" is also in the eyes of "typeof"
        // search again :D
        gvpio(currElem, maxDepth - 1, prefix + curr + "/")
        if (notObject) continue
      }
      // it's something else... probably the value we are looking for
      // compares with "searchValue"
      if (currElem === searchValue) {
        // return index AND/OR property name
        paths.push(prefix + curr)
      }
    }
  }
  gvpio(obj, maxDepth, "")
  return paths
}

Here, I’m also using an options object for convenience, with a smart default for searchKeys, since object keys are always strings, even in arrays:

console.log(findPaths([[[]],[[]]],0)) // []
console.log(findPaths([[[]],[[]]],'0')) // [ '0', '0/0', '1/0' ]

I’m also building the path string with no duplication. This includes eliminating the inner loop, since we never return an intermediary array back up. The reason prefix + curr occurs in 3 places is because in a real search, on most keys none of those conditions will happen, and almost never will two happen together.


Collapse

Expand


qm3ster profile image

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:

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' ] // :(


Collapse

Expand


killants profile image

Not used to see many arrow function (without being small ones, in array.map for example) so i got a bit confused with the parameter line :
{ searchKeys = typeof searchValue === «string», maxDepth = 20 } = {}

Would you mind to explain in a few words why it is there? :)

Thank you in advance.

qm3ster profile image

Sure, this doesn’t depend on it being an arrow function, can be in a function just as well.

This is the equivalent function:

function fn(arg) {
  if (arg === undefined) arg = {}
  let searchKeys = arg.searchKeys
  if (searchKeys === undefined) searchKeys = typeof searchValue === "string"
  let maxDepth = arg.maxDepth
  if (maxDepth === undefined) maxDepth = 20
  /* ... */
}

First, we replace the point access with destructuring:

function fn(arg) {
  if (arg === undefined) arg = {}
  let { searchKeys, maxDepth } = arg
  if (searchKeys === undefined) searchKeys = typeof searchValue === "string"
  if (maxDepth === undefined) maxDepth = 20
  /* ... */
}

Next, we replace the conditional expressions for defaults with defaults in destructuring AND default in parameter:

function fn(arg = {}) {
  const { // we can use const now because we won't be reassigning
    searchKeys = typeof searchValue === "string",
    maxDepth = 20
  } = arg
  /* ... */
}

Finally, to avoid having to think of a name for the short-lived arg binding, we can just YEET it right into the parameter list:

function fn({
  searchKeys = typeof searchValue === "string",
  maxDepth = 20
} = {}) {
  /* ... */
}

We could write it like this:

function fn(
  { 
    searchKeys = typeof searchValue === "string",
    maxDepth = 20
  } = {
    searchKeys: typeof searchValue === "string",
    maxDepth: 20
  }
) {
  /* ... */
}

But that’s just more verbose. Destructuring an empty object (if undefined is provided) is perfectly adequate, and gives defaults for all keys.

function fn(
  searchValue, // this is the v below that we are depending on, it has to come first.
  { searchKeys = typeof searchValue === "string", maxDepth = 20 } = {}
) {
  /* ... */
}


Collapse

Expand


killants profile image

killants

I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.

  • Location

    Óbidos, Portugal

  • Work

    Developer at NewOxygen

  • Joined

    Jan 31, 2019

Feb 4 ’19

  • Copy link

Hasn’t use «let» before to declare variables, will definitely use now ( Thanks to Sarah Chima for her post «dev.to/sarah_chima/var-let-and-con…» )! :D

Is «for of» more optimized for this kind of methods (recursive), instead of indexed ones ?

I had that «charSeparator» declared inside because at the time i made it i though leaving the option to choose the char used to be received in parameter (but then i just forgot it XD)

That variable «i» …. I just can’t even remember why was there ?? :/ My bad !

Tonight i won’t be able, but tomorrow right after work, will fix it ! ;)

Thanks a lot for your feedback Mihail :D


Collapse

Expand


qm3ster profile image

If you look in the replies to my above comment, I replied to myself (and then replied again to that comment) with new versions of the code.


Collapse

Expand


simlu profile image

I had a similar idea last year :) Take a look at object-scan and the filterFn function. Shows where requirements ultimately go haha


Collapse

Expand


killants profile image

killants

I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.

  • Location

    Óbidos, Portugal

  • Work

    Developer at NewOxygen

  • Joined

    Jan 31, 2019

May 27 ’19

  • Copy link

a look where ? sorry not finding «object-scan» as told… Would you mind sharing a link, please?
Thanks


Collapse

Expand


simlu profile image


Collapse

Expand


killants profile image

killants

I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.

  • Location

    Óbidos, Portugal

  • Work

    Developer at NewOxygen

  • Joined

    Jan 31, 2019

Feb 4 ’19

  • Copy link

I added to the gist, the optimized function provided by «Mihail Malostanidis» (dev.to/qm3ster) since it is way more «clean». I leaved the old one so you can compare with my first attempt and see the difference. You can always check Mihail comments on this post since he explains his approach to this.

Big thanks to Mihail for his help!!! :)


Collapse

Expand


qm3ster profile image

Was a fully single-recursive implementation part of the goal?


Collapse

Expand


killants profile image

killants

I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.

  • Location

    Óbidos, Portugal

  • Work

    Developer at NewOxygen

  • Joined

    Jan 31, 2019

Feb 4 ’19

  • Copy link

Was my way of thinking, i made this method just to fecth the path in some object which value i knew it exists somewhere. :)

For further actions, you may consider blocking this person and/or reporting abuse

Понравилась статья? Поделить с друзьями:
  • Как найти воду в болоте
  • Как исправить перекошенную вышивку
  • Как найти b14 геометрической прогрессии
  • Hdd стал raw как исправить без форматирования
  • Как найти мусульманский календарь