ryan
ryan

Reputation: 724

Nested Array Of Objects into Downloadable CSV in react

I have the following Data which when downloaded can be viewed in an xls/csv format. I am using react-csv npm package which is displaying the name and description in same columns as opposed to different columns.

I need some help in figuring out how to display data where Name, Description, and Roles are displayed in different columns as shown below.

Data:-

 const csvData = [
    {
        name: 'Data science training',
        description:
            'Data Science certification training',
        
       suggestedRoles: [
            { id: 16, category: 'DEVELOPER', name: 'Data Engineer' },
            { id: 17, category: 'DEVELOPER', name: 'Data Scientist' }]
        },{
         name: 'AWS',
        description:
            'AWS certification training',
        
       suggestedRoles: [
            { id: 16, category: 'DEVELOPER', name: 'Cloud Engineer' },
            { id: 17, category: 'DEVELOPER', name: 'Network Engineer' }]
}],

Expected Output:-

Name                        Description                                    RoleName
Data Science Training       Data Science Certification Training             Data Engineer
                                                                            Data Scientist
AWS Training                AWS Certification Training                      Cloud Engineer
                                                                            Network Engineer

Current Output:-

Name                                    Description                                                         RoleName
Data Science Training,AWS Training         Data Science Certification Training, AWS Certification Training    Data Engineer,Data Scientist,Cloud Engineer,Network Engineer

Code:-

export const ReactCsv = () => {
    const createCsvFileName = ()=> `data_${moment().format()}.csv`;
    const headers = [
        { label: 'Name', key: 'name' },
        { label: 'Description', key: 'description' },
        { label: 'SuggestedRoles', key: 'suggestedRoles' }
    ];

    const data = [
        {
            name: csvData.map((_)=>_.name),
            description: csvData.map((_)=>_.description),
            suggestedRoles: csvData.map((_)=>_.suggestedRoles.map((role)=>role.name)),
        }
    ];

    return (
        <CSVLink
            data={data}
            headers={headers}
            filename={createCsvFileName()}
            target="_blank"
            style={{ textDecoration: 'none', outline: 'none', height: '5vh' }}
        >
            <Button variant="contained" color="secondary" style={{ height: '100%' }}>
                Download CSV
            </Button>
        </CSVLink>
    );
};

Upvotes: 1

Views: 8493

Answers (3)

Sanjula De Alwis
Sanjula De Alwis

Reputation: 81

The data property should be one single object. So, what you can do is create a function that returns an object. That object structure you can decide based on the data and attributes you want to display.

eg:

 const newBillingReport = () => {
    try {
      const newBillingReportData =  billingExportReportData.map((data) => ({
        "Type": data?.type || "Not Provided",
        "Status": data?.status || "Not Provided",
        "Billed": data?.billedAmount || "0",
      }),[])

      return newBillingReportData
    } catch (error) {
      console.error(error)
    }
  }

This will returns object with three attributes:

eg:

{
  "Type": "COMPLETED",
  "Status": "DONE",
  "Billed": "True"
}

So like this you can create a function. Then for the header attribute map same as you returned. That should also will be a function that returns an object

eg:

const formatUserName = () => {
    return [
      { label: "Type", key: "Type" },
      { label: "Status", key: "Status" },
      { label: "Billed ($)", key: "Billed" },
    ]
  }

In here you can see how you need to add label and keys. Most likely the function return data.

So CVLink like this

headers={headers}
data={newBillingReport()}

headers should call the function const headers = formatUserName()

Upvotes: 0

LogiStack
LogiStack

Reputation: 1016

Your ReactCsv's data generating code should be changed into like this one.

export const ReactCsv = () => {
    const createCsvFileName = ()=> `data_${moment().format()}.csv`;
    const headers = [
        { label: 'Name', key: 'name' },
        { label: 'Description', key: 'description' },
        { label: 'SuggestedRoles', key: 'suggestedRoles' }
    ];

    let data = []
    csvData.forEach(item => {
        data.push({
            name: item.name,
            description: item.description,
            suggestedRoles: item.suggestedRoles[0].name
        });
        for (let i = 1; i < item.suggestedRoles.length; i++) {
            const role = item.suggestedRoles[i];
            data.push({
                name: '',
                description: '',
                suggestedRoles: role.name
            });
        }
    });

    return (
        <CSVLink
            data={data}
            headers={headers}
            filename={createCsvFileName()}
            target="_blank"
            style={{ textDecoration: 'none', outline: 'none', height: '5vh' }}
        >
            <Button variant="contained" color="secondary" style={{ height: '100%' }}>
                Download CSV
            </Button>
        </CSVLink>
    );
};

Upvotes: 2

Alex Chuev
Alex Chuev

Reputation: 713

The data variable must be an array of objects, not an array of a single object where each property is an array of values.

const csvData = [{
  name: 'Data science training',
  description: 'Data Science certification training',

  suggestedRoles: [{
      id: 16,
      category: 'DEVELOPER',
      name: 'Data Engineer'
    },
    {
      id: 17,
      category: 'DEVELOPER',
      name: 'Data Scientist'
    }
  ]
}, {
  name: 'AWS',
  description: 'AWS certification training',

  suggestedRoles: [{
      id: 16,
      category: 'DEVELOPER',
      name: 'Cloud Engineer'
    },
    {
      id: 17,
      category: 'DEVELOPER',
      name: 'Network Engineer'
    }
  ]
}];

const data = csvData.map(item => ({
  name: item.name,
  description: item.description,
  suggestedRoles: item.suggestedRoles.map(role => role.name),
}))

console.log(data);

Upvotes: 2

Related Questions