skip to Main Content

I am having an array of objects that looks like this

const input = [
  {
    group: {
      id: "group1",
      groupName: "Group1"
    },
    categories: [
      {
        id: "category11",
        categoryName: "Category 11",
        subCategories: []
      }
    ]
  },
  {
    group: {
      id: "group2",
      groupName: "Group 2"
    },
    categories: [
      {
        id: "category21",
        categoryName: "Category 21",
        subCategories: []
      },
      {
        id: "category22",
        categoryName: "Category 22",
        subCategories: [
          {
            id: "category221",
            categoryName: "Category 221",
            subCategories: []
          }
        ]
      }
    ]
  }
];

I want this array to be translated into below array of objects, with objects containing key, name and categories as its standard format to maintain the uniformity.

const output = [
  {
    key: "group1",
    name: "Group1",
    categories: [
      {
        key: "category11",
        name: "Category 11",
        categories: []
      }
    ]
  },
  {
    key: "group2",
    name: "Group 2",
    categories: [
      {
        key: "category21",
        name: "Category 21",
        categories: []
      },
      {
        key: "category22",
        name: "Category 22",
        categories: [
          {
            key: "category221",
            name: "Category 221",
            categories: []
          }
        ]
      }
    ]
  }
];

The first level of each object inside input should be considered as root in the final output and rest of items should be nested recursively inside this first level.

The code that I tried

const output = arr.map((item) => {
  return {
    key: item.group.id,
    name: item.group.groupName,
    categories: [{ ...item }]
  };
});

I was able to format the first level, but not the entire output. Can someone help me here?

4

Answers


  1. You can use recursivity for that

    function formatItem(item) {
        let categories = []
        if (item.categories?.length > 0) {
            for (category of item.categories) {
                categories.push(formatItem(category))
            }
        }
    
        if (item.subCategories?.length > 0) {
            for (category of item.subCategories) {
                categories.push(formatItem(category))
            }
        }
    
        return {
            key: item.group?.id ?? item.id,
            name: item.group?.groupName ?? item.categoryName,
            categories: categories
        };
    }
    
    const output = arr.map(formatItem);
    
    Login or Signup to reply.
  2. You could take a recursive approach with some renaming.

    const
        format = ({ id, categoryName, categories, subCategories, group: { id: key, groupName: name } = { id, groupName: categoryName } }) => ({
            key,
            name,
            categories: (categories || subCategories).map(format)
        }),
        input = [{ group: { id: "group1", groupName: "Group1" }, categories: [{ id: "category11", categoryName: "Category 11", subCategories: [] }] }, { group: { id: "group2", groupName: "Group 2" }, categories: [ { id: "category21", categoryName: "Category 21", subCategories: [] }, { id: "category22", categoryName: "Category 22", subCategories: [{ id: "category221", categoryName: "Category 221", subCategories: [] }] }] }],
        result = input.map(format);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  3. A simple recursive function:

    function refactor(object) {
      if (Object.hasOwn(object, 'group')) {
        // Is a group
        return {
          key: object.group.id,
          name: object.group.groupName,
          // Refactor all categories
          categories: object.categories.map(refactor)
        };
      }
    
      // Is a category
      return {
        key: object.id,
        name: object.categoryName,
        // Refactor all subcategories
        categories: object.subCategories.map(refactor)
      };
    }
    
    console.log(input.map(refactor))
    

    Try it:

    function refactor(object) {
      if (Object.hasOwn(object, 'group')) {
        // Is not a category
        return {
          key: object.group.id,
          name: object.group.groupName,
          categories: object.categories.map(refactor)
        };
      }
    
      // Is a category
      return {
        key: object.id,
        name: object.categoryName,
        categories: object.subCategories.map(refactor)
      };
    }
    
    const input = [{
        group: {
          id: 'group1',
          groupName: 'Group1'
        },
        categories: [{
          id: 'category11',
          categoryName: 'Category 11',
          subCategories: []
        }]
      },
      {
        group: {
          id: 'group2',
          groupName: 'Group 2'
        },
        categories: [{
            id: 'category21',
            categoryName: 'Category 21',
            subCategories: []
          },
          {
            id: 'category22',
            categoryName: 'Category 22',
            subCategories: [{
              id: 'category221',
              categoryName: 'Category 221',
              subCategories: []
            }]
          }
        ]
      }
    ];
    
    console.log(JSON.stringify(input.map(refactor), null, 2));
    .as-console-wrapper {
      max-height: 100% !important;
    }
    Login or Signup to reply.
  4. You can do that pretty efficiently when you use a map object which maps old property names to new ones:

    const data = [{ group: { id: "group1", groupName: "Group1" }, categories: [{ id: "category11", categoryName: "Category 11", subCategories: [] }] }, { group: { id: "group2", groupName: "Group 2" }, categories: [ { id: "category21", categoryName: "Category 21", subCategories: [] }, { id: "category22", categoryName: "Category 22", subCategories: [{ id: "category221", categoryName: "Category 221", subCategories: [] }] }] }]
    
    const renames = {
      id: 'key',
      groupName: 'name',
      categoryName: 'name',
      subCategories: 'categories',
    }
    const renameKeys = (obj) => Object.fromEntries(Object.entries(obj).map(([prop, value]) => [renames[prop] ?? prop, Array.isArray(value) ? value.map(renameKeys) : value]))
    const transform = (groups) => groups.map(({group, categories}) => renameKeys({...group, categories }))
    console.log(transform(data))
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search