0
const array = [
{ 
id: "1",
children: [],
messages:[1, 'Text'],
entry: "Father",
},

{
id: "2",
entry: "Mother",
children: [
    {entry: "John Jr"},
    {entry: "Steven Jr"},
    {entry: "Tim Jr"},
    ],
messages:[2, 'Text'],
}, 

{
id: "3",
entry: "Son",
children: [
    {entry: "XXX Jr"},
    {entry: "Steven Jr"},
    {entry: "Tim Jr"}
    ],
 messages:[3, 'Text'],
 },
]

So what I want here is, when I do the search "Tim". I want the output to be

Case 1: When I search for Tim, I should get the object with id: 2 and id: 3 because Tim is an entry matching in both the objects. so I want to return the entire id: 2 and 3 object in the same order.

{
id: "2",
entry: "Mother",
children: [
    {entry: "John Jr"},
    {entry: "Steven Jr"},
    {entry: "Tim Jr"},
    ],
messages:[2, 'Text'],
}, 

{
id: "3",
entry: "Son",
children: [
    {entry: "XXX Jr"},
    {entry: "Steven Jr"},
    {entry: "Tim Jr"}
    ],
 messages:[3, 'Text'],
 }

Case 2: When I search for John, I should get second object as

{
id: "2",
entry: "Mother",
children: [
    {entry: "John Jr"},
    ],
messages:[2, 'Text'],
}

Case 3: When I search for Steven, I should get id:2 and id:3 as

id: "2",
entry: "Mother",
children: [
    {entry: "John Jr"},
    {entry: "Steven Jr"},
    ],
messages:[2, 'Text'],
}, 

{
id: "3",
entry: "Son",
children: [
    {entry: "XXX Jr"},
    {entry: "Steven Jr"},
    ],
 messages:[3, 'Text'],
 }

I used .filter() to filter the top level but this isn't checking the children.

array.filter((item) => item.entry.toUpperCase().includes(text.toUpperCase())); 

Any help would be greatly appreciated as I'm totally lost with forEach here. Thanks in advance

7
  • USe array.filter(). The callback function should search the children array for matching names. Commented Nov 25, 2021 at 6:35
  • 1
    That can be done using array.some(). Commented Nov 25, 2021 at 6:35
  • And the callback function in some() can use element.entry.includes(name) where name is the name you're looking for. Commented Nov 25, 2021 at 6:36
  • @Barmar => I did try using filter array.filter((item) => item.entry.toUpperCase() .includes(text.toUpperCase())); This is not checking the children. I'll play with the callback. Thanks again :) Commented Nov 25, 2021 at 6:41
  • Post the code in the question, not a comment. Commented Nov 25, 2021 at 6:42

2 Answers 2

1

you can use Array.Filter , Array.some and splice the children array with index of the search entry object

const array = [{
    id: "1",
    children: [],
    messages: [1, 'Text'],
    entry: "Father",
  },

  {
    id: "2",
    entry: "Mother",
    children: [{
        entry: "John Jr"
      },
      {
        entry: "Steven Jr"
      },
      {
        entry: "Tim Jr"
      },
    ],
    messages: [2, 'Text'],
  },

  {
    id: "3",
    entry: "Son",
    children: [{
        entry: "XXX Jr"
      },
      {
        entry: "Steven Jr"
      },
      {
        entry: "Tim Jr"
      }
    ],
    messages: [3, 'Text'],
  },
];


let searchText = 'John';

let result = array.filter(el => {
  let i;
  let found = el.children.some((e, j) => {
    i = j;
    return e.entry.toLowerCase().indexOf(searchText.toLowerCase()) >= 0;
  });

  if (found)
    el.children = el.children.splice(0, i + 1);

  return found;
});

console.log(result);

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

Comments

1

const data=[{id:"1",children:[],messages:[1,"Text"],entry:"Father"},{id:"2",entry:"Mother",children:[{entry:"John Jr", children: [{entry: 'Bob', children: [{entry: 'Marvin'},{entry: 'Summer', children: [{entry: 'Batman'}, {entry: 'Robin'}]}]},{entry: 'Dave', children: [{entry: 'Sue'}, {entry: 'Sam'}]}]},{entry:"Steven Jr"},{entry:"Tim Jr"}],messages:[2,"Text"]},{id:"3",entry:"Son",children:[{entry:"XXX Jr", children: [{entry: 'Batman'}]},{entry:"Steven Jr"},{entry:"Tim Jr"}],messages:[3,"Text"]}];

function recurseChildren(children) {
  const arr = [];
  function loop(children) {
    for (const entry of children) {
      arr.push(entry.entry);
      if (entry.children) {
        loop(entry.children);
      }
    }
  }
  loop(children);
  return arr;
}

function finder(data, name) {

  // `filter` over the array
  return data.filter(obj => {

    // Recurse over the children array of all entries
    // to compile a list of names
    const names = recurseChildren(obj.children);

    // For each object check to see if
    // at least one of the entries in children
    // includes the name
    return names.some(entry => {
      return entry.includes(name);
    });

  });
}

console.log(finder(data, 'Tim'));
console.log(finder(data, 'John'));
console.log(finder(data, 'Steven'));
console.log(finder(data, 'Batman'));

2 Comments

You're a saviour Andy. What if you have a object like this? { id: "3", entry: "Son", children: [{ entry: "XXX Jr", children: [{ entry: "YYY Jr", children: [{ entry: "ZZZZ Jr" }], }], }, I kinda tried to use recursion here, but no luck as I got into infinite loop. What if you 100 sub children's like this?
The update should work with n nested children. @user2824374

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.