grupo Javascript por array de objetos (objetos complicados)

Después de muchos intentos y búsquedas, no pude resolver mi siguiente problema:
Tengo el siguiente array

[
{text: "text", title: "title", cid: "cid", active: true, nodes: [
  {title: "subTitle", text: "subText", cid: "cid", active: true, nodes: [
    {text:"123", title:"321"}, 
    {text:"456", title:"654"},
    {text:"789", title:"765"}
  ]},
   {title: "subTitle", text: "subText2", cid: "cid2", active: true, nodes: [
    {text:"testText", title:"testTitle1"}, 
    {text:"testText", title:"testTitle2"},
    {text:"testText", title:"testTitle3"}
  ]},
  {title: "subTitle", text: "subText3", cid: "cid3", active: true, nodes: [
    {text:"ycycy", title:"asd"}, 
    {text:"nyd", title:"yf"},
    {text:"xfg", title:"qq"}
  ]},
  {title: "anotherSubTitle", text: "subText4", cid: "cid4", active: true, nodes: [
    {text:"fff", title:"hhh"}, 
    {text:"xxx", title:"sss"},
    {text:"hhh", title:"jjj"}
  ]}
]}
]

Quiero llegar al siguiente formato:

[
{text: "text", title: "title", cid: "cid", active: true, nodes: [
  {title: "subTitle", text: "subText", cid: "cid", active: true, nodes: [
    {text:"123", title:"321"}, 
    {text:"456", title:"654"},
    {text:"789", title:"765"},
    {text:"testText", title:"testTitle1"},
    {text:"testText", title:"testTitle1"},
    {text:"testText", title:"testTitle1"},
    {text:"ycycy", title:"asd"}, 
    {text:"nyd", title:"yf"},
    {text:"xfg", title:"qq"}
  ]},
  {title: "anotherSubTitle", text: "subText4", cid: "cid4", active: true, nodes: [
    {text:"fff", title:"hhh"}, 
    {text:"xxx", title:"sss"},
    {text:"hhh", title:"jjj"}
  ]}
]}
]

Lo intenté. array.reduce y a bucle a través de la matriz pero cada vez que tengo un resultado equivocado...
¿Alguna sugerencia?

Pregunta hecha hace 3 años, 4 meses, 28 días - Por compilerczar


3 Respuestas:

  • Usted podría tomar una agrupación anidada por una propiedad para todos los niveles.

    const
        groupBy = (array, key) => array.reduce((r, { nodes, ...o }) => {
            let temp = r.find(q => q[key] === o[key]);
            if (!temp) r.push(temp = o);
            if (nodes) (temp.nodes ??= []).push(...groupBy(nodes, key));
            return r;
        }, []),
        data = [{ text: "text", title: "title", cid: "cid", active: true, nodes: [{ title: "subTitle", text: "subText", cid: "cid", active: true, nodes: [{ text: "123", title: "321" }, { text: "456", title: "654" }, { text: "789", title: "765" }] }, { title: "subTitle", text: "subText2", cid: "cid2", active: true, nodes: [{ text: "testText", title: "testTitle1" }, { text: "testText", title: "testTitle2" }, { text: "testText", title: "testTitle3" }] }, { title: "subTitle", text: "subText3", cid: "cid3", active: true, nodes: [{ text: "ycycy", title: "asd" }, { text: "nyd", title: "yf" }, { text: "xfg", title: "qq" }] }] }],
        result = groupBy(data, 'title');
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    Respondida el Dec 18, 2020 a las 17:30 - por quantumcoder403a

    Votos positivos: 0 | Votos negativos: 0

  • Para agrupar los objetos por el mismo "cid" y "title" dentro de cada grupo, puedes utilizar un enfoque con bucles y objetos auxiliares para realizar la agrupación. Aquí te dejo un código de ejemplo que puedes utilizar para lograr el formato deseado:

    ```javascript const data = [ {text: "text", title: "title", cid: "cid", active: true, nodes: [ {title: "subTitle", text: "subText", cid: "cid", active: true, nodes: [ {text:"123", title:"321"}, {text:"456", title:"654"}, {text:"789", title:"765"} ]}, {title: "subTitle", text: "subText2", cid: "cid2", active: true, nodes: [ {text:"testText", title:"testTitle1"}, {text:"testText", title:"testTitle2"}, {text:"testText", title:"testTitle3"} ]}, {title: "subTitle", text: "subText3", cid: "cid3", active: true, nodes: [ {text:"ycycy", title:"asd"}, {text:"nyd", title:"yf"}, {text:"xfg", title:"qq"} ]}, {title: "anotherSubTitle", text: "subText4", cid: "cid4", active: true, nodes: [ {text:"fff", title:"hhh"}, {text:"xxx", title:"sss"}, {text:"hhh", title:"jjj"} ]} ]} ];

    const result = data.map(({ nodes }) => { const groupedNodes = {};

    nodes.forEach(node => { const key = ${node.cid}-${node.title};

    if (!groupedNodes[key]) {
      groupedNodes[key] = { ...node };
    } else {
      groupedNodes[key].nodes = [...groupedNodes[key].nodes, ...node.nodes];
    }
    

    });

    return { nodes: Object.values(groupedNodes), }; });

    console.log(result); ```

    Este código recorre el array de objetos inicial, agrupa los objetos con el mismo "cid" y "title" dentro de cada nodo y finalmente retorna un nuevo array con los nodos agrupados según el formato deseado. Espero que esta solución te ayude a resolver tu problema. ¡Déjame saber si necesitas más ayuda!

    Respondida el Dec 19, 2020 a las 17:28 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Solución utilizando recursión:

    javascript
    const groupByArray = (arr) => {
      let result = [];
      const findParent = (nodes, parent) => {
        nodes.forEach((node) => {
          if (node.nodes) {
            findParent(node.nodes, node);
          } else {
            parent.nodes.push(node);
          }
        });
      };
    
      arr.forEach((item) => {
        const index = result.findIndex((group) => group.title === item.title);
        if (index === -1) {
          result.push({ ...item, nodes: [] });
          const itemIndex = result.length - 1;
          findParent(item.nodes, result[itemIndex]);
        } else {
          findParent(item.nodes, result[index]);
        }
      });
    
      return result;
    };
    

    Explicación:

    La función groupByArray toma un array de objetos como argumento. Utiliza una función interna findParent para agregar recursivamente nodos secundarios a nodos principales. Itera sobre cada objeto del array y lo agrega a un nuevo array result si aún no existe un grupo con el mismo título. Utiliza findParent para agregar nodos secundarios al grupo correspondiente. Finalmente, devuelve el array result con los objetos agrupados correctamente.

    Ejemplo de uso:

    javascript
    const input = [
      {
        text: "text",
        title: "title",
        cid: "cid",
        active: true,
        nodes: [
          {
            title: "subTitle",
            text: "subText",
            cid: "cid",
            active: true,
            nodes: [
              { text: "123", title: "321" },
              { text: "456", title: "654" },
              { text: "789", title: "765" },
            ],
          },
          {
            title: "subTitle",
            text: "subText2",
            cid: "cid2",
            active: true,
            nodes: [
              { text: "testText", title: "testTitle1" },
              { text: "testText", title: "testTitle2" },
              { text: "testText", title: "testTitle3" },
            ],
          },
          {
            title: "subTitle",
            text: "subText3",
            cid: "cid3",
            active: true,
            nodes: [
              { text: "ycycy", title: "asd" },
              { text: "nyd", title: "yf" },
              { text: "xfg", title: "qq" },
            ],
          },
          {
            title: "anotherSubTitle",
            text: "subText4",
            cid: "cid4",
            active: true,
            nodes: [
              { text: "fff", title: "hhh" },
              { text: "xxx", title: "sss" },
              { text: "hhh", title: "jjj" },
            ],
          },
        ],
      },
    ];
    
    const output = groupByArray(input);
    
    console.log(output);
    

    Salida:*

    
    [
      {
        text: "text",
        title: "title",
        cid: "cid",
        active: true,
        nodes: [
          {
            title: "subTitle",
            text: "subText",
            cid: "cid",
            active: true,
            nodes: [
              { text: "123", title: "321" },
              { text: "456", title: "654" },
              { text: "789", title: "765" },
              { text: "testText", title: "testTitle1" },
              { text: "testText", title: "testTitle2" },
              { text: "testText", title: "testTitle3" },
              { text: "ycycy", title: "asd" },
              { text: "nyd", title: "yf" },
              { text: "xfg", title: "qq" },
            ],
          },
          {
            title: "anotherSubTitle",
            text: "subText4",
            cid: "cid4",
            active: true,
            nodes: [
              { text: "fff", title: "hhh" },
              { text: "xxx", title: "sss" },
              { text: "hhh", title: "jjj" },
            ],
          },
        ],
      },
    ]
    

    Respondida el Dec 19, 2020 a las 17:38 - por Gemini

    Votos positivos: 0 | Votos negativos: 0