json-2-csv icon indicating copy to clipboard operation
json-2-csv copied to clipboard

Empty Array Being Returned as Header causing JSON to be Outputted in CSV

Open hdwatts opened this issue 3 years ago • 8 comments

Background Information

  • Module Version: 3.7.8
  • Node/Browser Version: 86.0.4240.80

The issue I'm reporting is with:

  • [x] json2csv
  • [ ] csv2json

I have...

  • [x] searched to see if an issue has already been reported.
  • [x] verified that my JSON/CSV data is valid (using something like http://jsonlint.com or https://csvlint.io/).
  • [x] tried upgrading to the latest version of json-2-csv (since the issue may already be fixed).

Expected Behavior

entities.id,entities.name,entities.siblings.entity.name,entities.siblings.relationship_set.relationships.relationship.name
4,Zeus,Exo,Senior
4,Zeus,Chrono,null

Actual Behavior

entities.id,entities.name,entities.siblings.entity.name,entities.siblings.relationship_set.relationships.relationship.name,entities.siblings.relationship_set.relationships
4,Zeus,Exo,Senior,"{""relationship"":{""name"":""Senior""}}"
4,Zeus,Chrono,null,

Data Sample

JSON:

{
  "entities":
    {
      "id": 4,
      "name": "Zeus",
      "siblings": [
        {
          "entity": {
            "name": "Exo",
          },
          "relationship_set": {
            "relationships": [
              {
                "relationship": {
                  "name": "Senior"
                },
              },
            ]
          }
        },
        {
          "entity": {
            "name": "Chrono"
          },
          "relationship_set": {
            "relationships": []
          }
        }
      ]
    }
}

Code Example

// Please include a simple example to replicate the issue
let converter = require('json-2-csv');
const obj1 = {
  "entities":
    {
      "id": 4,
      "name": "Zeus",
      "siblings": [
        {
          "entity": {
            "name": "Exo",
          },
          "relationship_set": {
            "relationships": [
              {
                "relationship": {
                  "name": "Senior"
                },
              },
            ]
          }
        },
        {
          "entity": {
            "name": "Chrono"
          },
          "relationship_set": {
            "relationships": []
          }
        }
      ]
    }
}

converter.json2csv(obj1, (err, csv) => {
    console.log(csv)
  }, { unwindArrays: true, expandArrayObjects: true })

hdwatts avatar Oct 20 '20 14:10 hdwatts

To note, while messing around I found a way to get the expected output, but do not think it is the correct solution as it causes a test to fail. I solved it by updating deeks.generateDeepKeysList to return no key if there is an array to recur on but it is empty:

} else if (isArrayToRecurOn(data[currentKey]) && !data[currentKey].length) {
    return []
}

and then changing json-2-csv.utils, where we "push an empty string so the value is empty since there are no values" to instead push an empty array instead of an empty string:

path.setPath(cloned, fieldPath, []);

This is obviously not the right solution, however it brings about the expected output and may help you find the correct solution.

hdwatts avatar Oct 20 '20 14:10 hdwatts

I'm having a similar issue, but with Objects. E.g.:

const test_json = [
    {
        a: 1,
        b: 2,
        c: {
            ca: 1,
            cb: 2,
        },
    },
    {
        a: 3,
        b: 4,
        c: {},
    },
]

json2csvAsync(test_json).then(console.log) //?

result:

a,b,c.ca,c.cb,c 
1,2,1,2,"{""ca"":1,""cb"":2}" 
3,4,undefined,undefined,{} 

I've looked through the docs to see how I might address this, but I've come up with nothing... Any tips?

🙏

loganpowell avatar Jan 20 '22 21:01 loganpowell

@loganpowell I switched to https://github.com/kaue/jsonexport but I recommend using my fork from this PR: https://github.com/kaue/jsonexport/pull/90

hdwatts avatar Jan 20 '22 21:01 hdwatts

@hdwatts I tried that, but that leaves something to be desired as well. I'll follow up on that PR. with more info

loganpowell avatar Jan 20 '22 23:01 loganpowell

I've used a work around to make sure a null set is present to keep the object structures similar and that is working for me atm... e.g.:

const test_json = [
    {
        a: 1,
        b: 2,
        c: {
            ca: 1,
            cb: 2,
        },
    },
    {
        a: 3,
        b: 4,
        c: {},
    },
]

const xfd = test_json.reduce((acc, cur) => {
    const null_set = { ca: null, cb: null }
    const { c, ...rest } = cur
    return acc.push({ ...((c.ca && { c }) || { c: null_set }), ...rest }), acc
}, [])
json2csvAsync(xfd).then(console.log) //?

result:

c.ca,c.cb,a,b 
1,2,1,2 
null,null,3,4 

loganpowell avatar Jan 20 '22 23:01 loganpowell

Hit the same issue as @loganpowell with an empty object yielding an unwanted JSON-filled column. Used a similar workaround.

bmish avatar Feb 14 '24 21:02 bmish

Thanks for bringing this up again. I'm trying to make some progress on these issues and will take another look to see if I can find a solution to resolve this since I agree that the behavior of printing a JSON object's representation isn't ideal.

mrodrig avatar Feb 25 '24 05:02 mrodrig

It happens the same to me

alinpr18 avatar Mar 03 '24 18:03 alinpr18