Home > database >  Invert data structure while deduplicating
Invert data structure while deduplicating

Time:12-16

I have a complicated task I am trying to find a solution. I have the following data structure

data = [
    {
        "id": 1,
        "attributes": {
            "name": "Mother of All Topics",
            "info": "Notice",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 2,
        "attributes": {
            "name": "Important Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 1,
                    "attributes": {
                        "name": "Mother of All Topics",
                        "info": "Notice",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 3,
        "attributes": {
            "name": "Critical Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 2,
                    "attributes": {
                        "name": "Important Topic",
                        "info": null,
                        "parentTopic": {
                            "data": {
                                "id": 1,
                                "attributes": {
                                    "name": "Mother of All Topics",
                                    "info": "Notice",
                                    "parentTopic": {
                                        "data": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "id": 5,
        "attributes": {
            "name": "Another Important Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 1,
                    "attributes": {
                        "name": "Mother of All Topics",
                        "info": "Notice",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 6,
        "attributes": {
            "name": "Demo Demo Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 5,
                    "attributes": {
                        "name": "Another Important Topic",
                        "info": null,
                        "parentTopic": {
                            "data": {
                                "id": 1,
                                "attributes": {
                                    "name": "Mother of All Topics",
                                    "info": "Notice",
                                    "parentTopic": {
                                        "data": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "id": 7,
        "attributes": {
            "name": "Some Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 5,
                    "attributes": {
                        "name": "Another Important Topic",
                        "info": null,
                        "parentTopic": {
                            "data": {
                                "id": 1,
                                "attributes": {
                                    "name": "Mother of All Topics",
                                    "info": "Notice",
                                    "parentTopic": {
                                        "data": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "id": 9,
        "attributes": {
            "name": "Nice Topic",
            "info": "Critical note",
            "parentTopic": {
                "data": {
                    "id": 1,
                    "attributes": {
                        "name": "Mother of All Topics",
                        "info": "Notice",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 10,
        "attributes": {
            "name": "Super Critical Topic",
            "info": "Critical note",
            "parentTopic": {
                "data": {
                    "id": 9,
                    "attributes": {
                        "name": "Nice Topic",
                        "info": "Critical note",
                        "parentTopic": {
                            "data": {
                                "id": 1,
                                "attributes": {
                                    "name": "Mother of All Topics",
                                    "info": "Notice",
                                    "parentTopic": {
                                        "data": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "id": 11,
        "attributes": {
            "name": "Just Another Example Topic",
            "info": null,
            "parentTopic": {
                "data": {
                    "id": 10,
                    "attributes": {
                        "name": "Super Critical Topic",
                        "info": "Critical note",
                        "parentTopic": {
                            "data": {
                                "id": 9,
                                "attributes": {
                                    "name": "Nice Topic",
                                    "info": "Critical note",
                                    "parentTopic": {
                                        "data": {
                                            "id": 1,
                                            "attributes": {
                                                "name": "Mother of All Topics",
                                                "info": "Notice",
                                                "parentTopic": {
                                                    "data": null
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "id": 22,
        "attributes": {
            "name": "Nested Important Topic",
            "info": "",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 23,
        "attributes": {
            "name": "Nice Topic",
            "info": "",
            "parentTopic": {
                "data": {
                    "id": 22,
                    "attributes": {
                        "name": "Nested Important Topic",
                        "info": "",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 24,
        "attributes": {
            "name": "Critical Top Level",
            "info": "",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 25,
        "attributes": {
            "name": "Nice Topic",
            "info": "",
            "parentTopic": {
                "data": {
                    "id": 24,
                    "attributes": {
                        "name": "Critical Top Level",
                        "info": "",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 26,
        "attributes": {
            "name": "Stakeholder Management",
            "info": "Noice",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 27,
        "attributes": {
            "name": "Conflict Resolution",
            "info": "Watch out",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 28,
        "attributes": {
            "name": "International Resolution",
            "info": "Watch out",
            "parentTopic": {
                "data": null
            }
        }
    },
    {
        "id": 29,
        "attributes": {
            "name": "Gadget Management",
            "info": "",
            "parentTopic": {
                "data": {
                    "id": 25,
                    "attributes": {
                        "name": "Nice Topic",
                        "info": "",
                        "parentTopic": {
                            "data": {
                                "id": 24,
                                "attributes": {
                                    "name": "Critical Top Level",
                                    "info": "",
                                    "parentTopic": {
                                        "data": null
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
]

I have tried with the following function to invert it by applying it to the array of dictionaries, while it is a recursive function for some reason it only works with one nested level.

// construct prefix
const getPrefix = (prefix, i) =>
  prefix ? `${prefix}.${i   1}` : `${i   1}`;

// invert hierarchy
const invertHierarchy = (arr, parentTopic, prefix) =>
  arr
    .filter((e) => e.parentTopic.data?.id === parentTopic)
    .map((e, i) => ({
      ...e,
      index: getPrefix(prefix, i),
      topics: invertHierarchy(arr, e.id, getPrefix(prefix, i)),
    }));

The output result that I am aiming for looks like this

[
    {
        "id": 1,
        "name": "Mother of All Topics",
        "topics": [
            {
                "id": 2,
                "name": "Important Topic",
                "info": null,
                "topics": [
                    {
                        "id": 3,
                        "name": "Critical Topic",
                        "topics": [

                        ]
                    }
                ]
            }
        ]  
    },
    {
        "id": 24,
        "name": "Critical Top Level",
        "topics": [
            {
                "id": 25,
                "name": "Nice Topic",
                "info": null,
                "topics": [
                    {
                        "id": 29,
                        "name": "Gadget Management",
                        "topics": null
                    }
                ]
            }
        ]  
    },
    ...
]

Essentiall, my end goal is to end up with inverted & deduplicated data structure where every parent topic goes to the top and all children are nested correctly inside topics array.

I would appreciate if someone could help with this challenge

!UPDATED

[
  {
    id: 22,
    attributes: {
      name: 'Nested Important Topic',
      info: '',
      createdAt: '2022-12-06T13:37:51.626Z',
      updatedAt: '2022-12-06T13:37:51.691Z',
      parentTopic: [Object],
      questions: [Object]
    }
  },
  {
    id: 23,
    attributes: {
      name: 'Nice Topic',
      info: '',
      parentTopic: {
        data: {
          id: 36,
          name: "Critical High Level Topic",
          info: ''
        }
      },
      questions: [Object]
    }
  },
  {
    id: 25,
    attributes: {
      name: 'Nice Topic',
      info: '',
      parentTopic: [Object],
      questions: [Object]
    }
  }
]

Futher UPDATE!

Input

[
    {
        "id": 25,
        "attributes": {
            "name": "Nice Topic",
            "info": "",
            "parentTopic": {
                "data": {
                    "id": 24,
                    "attributes": {
                        "name": "Critical Top Level",
                        "info": "",
                        "parentTopic": {
                            "data": null
                        }
                    }
                }
            }
        }
    },
    {
        "id": 23,
        "attributes": {
            "name": "Nice Topic",
            "info": "",
            "parentTopic": {
                "data": {
                    "id": 22,
                    "attributes": {
                        "name": "Nested Important Topic",
                        "info": "",
                        "parentTopic": {
                            "data": null
                        },
                    }
                }
            },
        }
    },
    {
        "id": 22,
        "attributes": {
            "name": "Nested Important Topic",
            "info": "",
            "parentTopic": {
                "data": null
            }
        }
    }
],

Output!

[
    {
        "id": 24,
        "name": "Critical Top Level",
        "info": "",
        "topics": [
            {
                "id": 25,
                "name": "Nice Topic",
                "info": "",
                "topics": []
            }
        ]
    },
    {
        "id": 22,
        "name": "Nested Important Topic",
        "info": "",
        "topics": [
            {
                "id": 23,
                "name": "Nice Topic",
                "info": "",
                "topics": []
            }
        ]
    },
    {
        "id": 22,
        "name": "Nested Important Topic",
        "info": "",
        "topics": []
    }
],

CodePudding user response:

Your input structure looks like it has repeated objects, and probably originally has duplicate references to the same object (so not JSON-like).

I'll assume that if in one area of the input we see that 24 is the parent of 25, this will also be true when we encounter node 25 elsewhere. In other words, an item has only one parent.

You can reverse the data structure by first collecting the objects in a Map keyed by their id, and then associate each id with a new object that has id, name and topics properties. The first two can be set immediately, while the topics property will start as an empty array.

For each object you could recursively walk the path to the ancestors and then while backtracking store the item in the parent's topics array.

Here is an implementation:

function reverseGraph(data) {
    const rootTopics = [];
    const map = new Map([[undefined, rootTopics]]);
    
    function upward({id, attributes: {name, parentTopic: {data: parent}}}) {
         if (map.has(id)) return map.get(id);
         const topics = [];
         map.set(id, topics);
         (parent ? upward(parent) : rootTopics).push({id, name, topics});
         return topics;
    }
    
    data.forEach(upward);
    return rootTopics;
}

// Your example data:
const data = [{"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}},{"id": 2,"attributes": {"name": "Important Topic","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}},{"id": 3,"attributes": {"name": "Critical Topic","parentTopic": {"data": {"id": 2,"attributes": {"name": "Important Topic","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}}}}},{"id": 5,"attributes": {"name": "Another Important Topic","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}},{"id": 6,"attributes": {"name": "Demo Demo Topic","parentTopic": {"data": {"id": 5,"attributes": {"name": "Another Important Topic","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}}}}},{"id": 7,"attributes": {"name": "Some Topic","parentTopic": {"data": {"id": 5,"attributes": {"name": "Another Important Topic","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}}}}},{"id": 9,"attributes": {"name": "Nice Topic","info": "Critical note","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}},{"id": 10,"attributes": {"name": "Super Critical Topic","info": "Critical note","parentTopic": {"data": {"id": 9,"attributes": {"name": "Nice Topic","info": "Critical note","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}}}}},{"id": 11,"attributes": {"name": "Just Another Example Topic","parentTopic": {"data": {"id": 10,"attributes": {"name": "Super Critical Topic","info": "Critical note","parentTopic": {"data": {"id": 9,"attributes": {"name": "Nice Topic","info": "Critical note","parentTopic": {"data": {"id": 1,"attributes": {"name": "Mother of All Topics","parentTopic": {"data": null}}}}}}}}}}}},{"id": 22,"attributes": {"name": "Nested Important Topic","parentTopic": {"data": null}}},{"id": 23,"attributes": {"name": "Nice Topic","parentTopic": {"data": {"id": 22,"attributes": {"name": "Nested Important Topic","parentTopic": {"data": null}}}}}},{"id": 24,"attributes": {"name": "Critical Top Level","parentTopic": {"data": null}}},{"id": 25,"attributes": {"name": "Nice Topic","parentTopic": {"data": {"id": 24,"attributes": {"name": "Critical Top Level","parentTopic": {"data": null}}}}}},{"id": 26,"attributes": {"name": "Stakeholder Management","info": "Noice","parentTopic": {"data": null}}},{"id": 27,"attributes": {"name": "Conflict Resolution","parentTopic": {"data": null}}},{"id": 28,"attributes": {"name": "International Resolution","parentTopic": {"data": null}}},{"id": 29,"attributes": {"name": "Gadget Management","parentTopic": {"data": {"id": 25,"attributes": {"name": "Nice Topic","parentTopic": {"data": {"id": 24,"attributes": {"name": "Critical Top Level","parentTopic": {"data": null}}}}}}}}}];

const result = reverseGraph(data);
console.log(result);

  • Related