Recursively Find and Modify the Data from Database

Viewed 52

I have this kind of table (or data structure)

enter image description here

There is parentIdeaId that refers to the id in ideas table itself.

Here's my unstructured data (please bear in mind this is the existing data in the database, not data that is already as it is so I have to query this first under some condition)

[{
    "id": "1",
    "title": "Title 1",
    "parentIdeaId": null
},{
    "id": "2",
    "title": "Title 2",
    "parentIdeaId": 1
},{
    "id": "3",
    "title": "Title 3",
    "parentIdeaId": 2
}]

I also made a function to find the data (I'm using Prisma in my real code)

function find({ id }) {
  return prisma.idea.findUnique({
    where: {
      id
    }
  });
}

And a function to find the children

function responseIdeas({ parentIdeaId }) {
  return prisma.idea.findMany({
    where: {
      parentIdeaId
    }
  });
}

I want the data to be nested like this

[{
    "id": "1",
    "title": "Title 1",
    "parentIdeaId": null,
    "responses": [
        {
            "id": "2",
            "title": "Title 2",
            "parentIdeaId": 1,
            "responses": [
                {
                    "id": "3",
                    "title": "Title 3",
                    "parentIdeaId": 2,
                    "responses": []
                }
            ]
        }
    ]
}]

So I made a recursive function

async function detail({ id }) {
  const findChildren = async ({ id }) => {
    const idea = await find({ id });
    const responses = await responseIdeas({ parentIdeaId: id });
    if (responses.length !== 0) {
      const resolveResponses = await Promise.all(
        responses.map(async ({ id, ...rest }) => {
          const children = await findChildren({ id });
          return {
            id,
            ...rest,
            responses: children
          };
        })
      );
      return {
        ...idea,
        responses: resolveResponses
      };
    }
    return { ...idea };
  };

  return findChildren({ id });;
}

But it ended up being like this

[{
    "id": 1,
    "title": "Title 1",
    "parentIdeaId": null,
    "responses": [
        {
            "id": 2,
            "title": "Title 2",
            "parentIdeaId": 1,
            "responses": {
                "id": 2,
                "title": "Title 2",
                "parentIdeaId": 1,
                "responses": [
                    {
                        "id": 3,
                        "title": "Title 3",
                        "parentIdeaId": 2,
                        "responses": {
                            "id": 3,
                            "title": "Title 3",
                            "parentIdeaId": 2
                        }
                    }
                ]
            }
        }
    ]
}]

Where did I mess up? Thanks

1 Answers

When you map your responses, you only have to return children, not an object with responses: children.

const data = [{
    "id": "1",
    "title": "Title 1",
    "parentIdeaId": null
},{
    "id": "2",
    "title": "Title 2",
    "parentIdeaId": 1
},{
    "id": "3",
    "title": "Title 3",
    "parentIdeaId": 2
}];

function find({ id }) {
  return data.find((e) => e.id === id);
}

function responseIdeas({ parentIdeaId }) {
  return data.filter((e) => e.parentIdeaId == parentIdeaId);
}

async function detail({ id }) {
  const findChildren = async ({ id }) => {
    const idea = await find({ id });
    const responses = await responseIdeas({ parentIdeaId: id });
    if (responses.length !== 0) {
      const resolveResponses = await Promise.all(
        responses.map(async ({ id, ...rest }) => {
          const children = await findChildren({ id });
          return children; // <<---------------- modification
        })
      );
      return {
        ...idea,
        responses: resolveResponses
      };
    }
    return { ...idea };
  };

  return findChildren({ id });;
}

async function run() {
  const result = await detail({id: "1"});
  console.log(result);
}

run();

Related