Lo que hice fue lo siguiente:
1- Recorrer el arreglo original (dataResponse[]) y crear dos nuevos arreglos:
a) levelsArray[][], en el que cada posición del mismo representa uno de los niveles, y colocar en cada una un arreglo con los objetos de dataResponse[] en el arreglo correspondiente a su nivel (si tuviese tres niveles, quedando algo como levelsArray = [[objeto, objeto], [objeto, objeto, objeto], [objeto, objeto]]); y
b) filteredArray[][], parecido al anterior, pero colocando en cada una de las posiciones un arreglo con los objetos de ese nivel que cumplen con el criterio de búsqueda. En caso de que no haya ninguno, la posición se completa con un arreglo vacío. En base al ejemplo anterior y si sólo el primer nivel tuviese un único objeto que cumple, quedaría filteredArray = [[objeto], [], []].
2- Hacer una copia de filteredArray[][], llamada menuArray[][].
3- Recorrer cada arreglo de menuArray[][] en sentido inverso y agregar a los hijos y al padre que no están en filteredArray[][] de cada objeto en el arreglo correspondiente a su nivel (tomándolos de levelsArray[][]). Según el ejemplo anterior, podría quedar menuArray = [[objeto], [objeto], []]. Para evitar traer hijos de más, el objeto del que se traerán su padre e hijos debe estar en filteredArray[][].
4- Recorrer de forma ascendente menuArray[][] y traer a toda la descendencia de los objetos que cumplen con la búsqueda y no fueron añadidos en el paso anterior. Para esto basta fijarse si dicho objeto está en filteredArray[][]. De esta forma, menuArray = [[objeto], [objeto], [objeto]].
5- Crear un arreglo de arreglos menuArrayNoNesting[][] donde los objetos de menuArray[][] pasan a tener el atributo children = [].
6- Recorrer menuArrayNoNesting[][] de manera inversa y anidar a los hijos en el atributo children de sus padres correspondientes, creando un arreglo menuFiltered[] que vuelve a tener la estructura de dataResponse[], pero con los objetos filtrados según los criterios especificados.
1- Recorrer el arreglo original (dataResponse[]) y crear dos nuevos arreglos:
a) levelsArray[][], en el que cada posición del mismo representa uno de los niveles, y colocar en cada una un arreglo con los objetos de dataResponse[] en el arreglo correspondiente a su nivel (si tuviese tres niveles, quedando algo como levelsArray = [[objeto, objeto], [objeto, objeto, objeto], [objeto, objeto]]); y
b) filteredArray[][], parecido al anterior, pero colocando en cada una de las posiciones un arreglo con los objetos de ese nivel que cumplen con el criterio de búsqueda. En caso de que no haya ninguno, la posición se completa con un arreglo vacío. En base al ejemplo anterior y si sólo el primer nivel tuviese un único objeto que cumple, quedaría filteredArray = [[objeto], [], []].
2- Hacer una copia de filteredArray[][], llamada menuArray[][].
3- Recorrer cada arreglo de menuArray[][] en sentido inverso y agregar a los hijos y al padre que no están en filteredArray[][] de cada objeto en el arreglo correspondiente a su nivel (tomándolos de levelsArray[][]). Según el ejemplo anterior, podría quedar menuArray = [[objeto], [objeto], []]. Para evitar traer hijos de más, el objeto del que se traerán su padre e hijos debe estar en filteredArray[][].
4- Recorrer de forma ascendente menuArray[][] y traer a toda la descendencia de los objetos que cumplen con la búsqueda y no fueron añadidos en el paso anterior. Para esto basta fijarse si dicho objeto está en filteredArray[][]. De esta forma, menuArray = [[objeto], [objeto], [objeto]].
5- Crear un arreglo de arreglos menuArrayNoNesting[][] donde los objetos de menuArray[][] pasan a tener el atributo children = [].
6- Recorrer menuArrayNoNesting[][] de manera inversa y anidar a los hijos en el atributo children de sus padres correspondientes, creando un arreglo menuFiltered[] que vuelve a tener la estructura de dataResponse[], pero con los objetos filtrados según los criterios especificados.