mrodrig / json-2-csv

Convert JSON to CSV *or* CSV to JSON!
https://mrodrig.github.io/json-2-csv
MIT License
420 stars 58 forks source link

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

Open hdwatts opened 4 years ago

hdwatts commented 4 years ago

Background Information

The issue I'm reporting is with:

I have...

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 commented 4 years ago

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.

loganpowell commented 2 years ago

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?

🙏

hdwatts commented 2 years ago

@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

loganpowell commented 2 years ago

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

loganpowell commented 2 years ago

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 
bmish commented 9 months ago

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

mrodrig commented 8 months ago

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.

alinpr18 commented 8 months ago

It happens the same to me