1

I Need to find multiple elements in a nested array and return it as an array.

I use the reduce function to find the elements, but it returns only one record.

Nested array:

{
    "type": "group",
    "level": 0,
    "expand": "-closed",
    "selected": false,
    "text": "Федулов Владислав Владиславович",
    "phoneNumber": "+7 (927) 999 9999",
    "email": "[email protected]",
    "id": 24,
    "parent": null,
    "cardType": 0,
    "childrens": [
      {
        "type": "group",
        "level": 1,
        "expand": "-closed",
        "selected": false,
        "text": "Ширяев Феликс Богуславович",
        "phoneNumber": "+7 (123) 456 7810",
        "email": "[email protected]",
        "id": 47,
        "parent": 24,
        "cardType": 0,
        "childrens": [
          {
            "type": "manager",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Колесова Анастасия Олеговна",
            "phoneNumber": "+7 (900) 000 0001",
            "email": "[email protected]",
            "id": 58,
            "parent": 47,
            "cardType": 0,
            "childrens": null
          }
        ]
      }
    ]
  },
  {
    "type": "group",
    "level": 0,
    "expand": "-closed",
    "selected": false,
    "text": "Игнатьева Женевьева Павловна",
    "phoneNumber": "+7 (777) 777 7777",
    "email": "[email protected]",
    "id": 3,
    "parent": null,
    "cardType": 0,
    "childrens": [
      {
        "type": "group",
        "level": 1,
        "expand": "-closed",
        "selected": false,
        "text": "Меретин Викентий Васильевич",
        "phoneNumber": "+7 (917) 193 5222",
        "email": "[email protected]",
        "id": 2,
        "parent": 3,
        "cardType": 1,
        "childrens": [
          {
            "type": "manager",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Климаков Алексей Александрович",
            "phoneNumber": "+7 (903) 888 8888",
            "email": "[email protected]",
            "id": 20,
            "parent": 2,
            "cardType": 1,
            "childrens": null
          }
        ]
      }
    ]
  }

and the reduce function:

    var array = store.managersTree.treeNodes;
    var items = [];

    const findItemNested = (arr, searchString, nestingKey) => (
    arr.reduce((a, item) => {
         if (a) return a;
         if (item.text.indexOf(searchString)!==-1 || 
             item.phoneNumber.indexOf(searchString)!==-1 || 
             item.email.indexOf(searchString)!==-1) return item;
         if (item[nestingKey]) return findItemNested(item[nestingKey], 
       searchString, nestingKey)
    }, [])
    );

    const element = findItemNested(array, searchString, "childrens");

I am trying to find a record matching at least one criteria, expecting that reduce returns multiple records, but this returns only one record, despite there were multiple records found.

Any help would be appreciated.

UPD: searchString could be string like phoneNumber, text or email

3
  • Please add the output for a sample searchString. Not sure if you want objects from the nested childrens included as separate items in the output or just the objects from the main array Commented Jun 4, 2019 at 6:08
  • edited the question Commented Jun 4, 2019 at 6:59
  • No, I got that the searchString could either of those 3 fields by checking the code. Just wanted an output for a sample searchString. Like what would be the output for findItemNested(array, "@gmail.com", "childrens") Anyway I have added an answer Commented Jun 4, 2019 at 7:04

3 Answers 3

3

You could reduce the array recursively.

  • Destructure the object in reduce parameter to get nestingKey and other properties separately
  • Create an array of filterKeys which have the keys which you want to search for searchString.
  • Use some to check if any of the fields in the object have a value which includes the searchString.
  • If nestingKey exists, you can push the nested items to the accumulator array.

const input=[{"type":"group","level":0,"expand":"-closed","selected":false,"text":"Федулов Владислав Владиславович","phoneNumber":"+7 (927) 999 9999","email":"[email protected]","id":24,"parent":null,"cardType":0,"childrens":[{"type":"group","level":1,"expand":"-closed","selected":false,"text":"Ширяев Феликс Богуславович","phoneNumber":"+7 (123) 456 7810","email":"[email protected]","id":47,"parent":24,"cardType":0,"childrens":[{"type":"manager","level":2,"expand":"-empty","selected":false,"text":"Колесова Анастасия Олеговна","phoneNumber":"+7 (900) 000 0001","email":"[email protected]","id":58,"parent":47,"cardType":0,"childrens":null}]}]},{"type":"group","level":0,"expand":"-closed","selected":false,"text":"Игнатьева Женевьева Павловна","phoneNumber":"+7 (777) 777 7777","email":"[email protected]","id":3,"parent":null,"cardType":0,"childrens":[{"type":"group","level":1,"expand":"-closed","selected":false,"text":"Меретин Викентий Васильевич","phoneNumber":"+7 (917) 193 5222","email":"[email protected]","id":2,"parent":3,"cardType":1,"childrens":[{"type":"manager","level":2,"expand":"-empty","selected":false,"text":"Климаков Алексей Александрович","phoneNumber":"+7 (903) 888 8888","email":"[email protected]","id":20,"parent":2,"cardType":1,"childrens":null}]}]}],
    filterKeys = ["text", "phoneNumber", "email"];

function findItemNested(array, searchString, nestingKey) {
  return array.reduce((acc, { [nestingKey]: nested, ...o }) => {
    if (filterKeys.some(k => o[k] && o[k].includes(searchString)))
      acc.push(o)
      
    if (nested)
      acc.push(...findItemNested(nested, searchString, nestingKey)) 
      
    return acc;
  }, [])
}

console.log(findItemNested(input, "keshman", "childrens"))
console.log(findItemNested(input, "@gmail.com", "childrens"))

Sign up to request clarification or add additional context in comments.

7 Comments

exactly what i looking for. Now it return matched records with children. Can i filter it to only matched, without children?
@NastyaKeller updated. You can destructure the nestingKey out in the parameter and put the remaining properties in o. Now o will have every property but childrens. And, use nested variable in the if condition if(nested)
thank you so much! one more question - what means dots in this line acc.push(...findItemNested(nested, searchString, nestingKey))
@NastyaKeller that's spread syntax. Since the recursive call to findItemNested returns an array, if you push it to the accumulator, it will create a 2D array. Let's say: var a = [1]; var b = [2, 3] If you do a.push(b), it creates [1, [2, 3]]. So, you need to spread the array. a.push(...b) is similar to a.push(2, 3).
@NastyaKeller alternatively, you could do acc = acc.concat(findItemNested(..)) if it's too confusing
|
0

Always Array.reduce returns a single value after processing each element in the array. If you want to return matching records in array then you can use, Array.filter,

[1,2,3,4,5].filter((element) => {
    return (element === 2 || element ===4);
});

For this above code, the filtered array will be,

[2,4]

And before filter you should either flat the array or should traverse each and every element to filter the array instead of using Array.filter()

2 Comments

It's Array.prototype.filter, there's no Array.filter. It's different
Sorry missed prototype there!
0

Without reduce also its possible,

var s = [{
    "type": "group",
    "level": 0,
    "expand": "-closed",
    "selected": false,
    "text": "Федулов Владислав Владиславович",
    "phoneNumber": "+7 (927) 999 9999",
    "email": "[email protected]",
    "id": 24,
    "parent": null,
    "cardType": 0,
    "childrens": [
      {
        "type": "group",
        "level": 1,
        "expand": "-closed",
        "selected": false,
        "text": "Ширяев Феликс Богуславович",
        "phoneNumber": "+7 (123) 456 7810",
        "email": "[email protected]",
        "id": 47,
        "parent": 24,
        "cardType": 0,
        "childrens": [
          {
            "type": "manager",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Колесова Анастасия Олеговна",
            "phoneNumber": "+7 (900) 000 0001",
            "email": "[email protected]",
            "id": 58,
            "parent": 47,
            "cardType": 0,
            "childrens": null
          },
          {
            "type": "group",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Колесова Анастасия Олеговна",
            "phoneNumber": "+7 (900) 000 0001",
            "email": "[email protected]",
            "id": 534,
            "parent": 47,
            "cardType": 0,
            "childrens": null
          },
          {
            "type": "manager",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Колесова Анастасия Олеговна",
            "phoneNumber": "+7 (900) 000 0001",
            "email": "[email protected]",
            "id": 523,
            "parent": 47,
            "cardType": 0,
            "childrens": null
          }
        ]
      }
    ]
  },
  {
    "type": "manager",
    "level": 0,
    "expand": "-closed",
    "selected": false,
    "text": "Игнатьева Женевьева Павловна",
    "phoneNumber": "+7 (777) 777 7777",
    "email": "[email protected]",
    "id": 3,
    "parent": null,
    "cardType": 0,
    "childrens": [
      {
        "type": "group",
        "level": 1,
        "expand": "-closed",
        "selected": false,
        "text": "Меретин Викентий Васильевич",
        "phoneNumber": "+7 (917) 193 5222",
        "email": "[email protected]",
        "id": 2,
        "parent": 3,
        "cardType": 1,
        "childrens": [
          {
            "type": "manager",
            "level": 2,
            "expand": "-empty",
            "selected": false,
            "text": "Климаков Алексей Александрович",
            "phoneNumber": "+7 (903) 888 8888",
            "email": "[email protected]",
            "id": 20,
            "parent": 2,
            "cardType": 1,
            "childrens": null
          }
        ]
      }
    ]
  }];

  function filterRequiredElement(arr, searchString, nestingKey) {
      arr.forEach((item, index) => {
          if (item.type !== searchString || item.phoneNumber !== searchString || item.email !== searchString) {
             arr.splice(index, 1);
          }
      });
      for(let item of arr) {
          if (item[nestingKey] !== null) {
              filterRequiredElement(item[nestingKey], searchString, nestingKey);
          }
      }
  }

  filterRequiredElement(s ,'Климаков Алексей Александрович', 'childrens');
  console.log(s);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.