neo5_50
neo5_50

Reputation: 476

Can't flatten JSON array to prepare for CSV conversion using Ruby 2.1.4

I have an array of nested JSON "hash" objects that I need to completely flatten so it ports over to CSV cleanly, which is obviously not nested and "multidimensional" like JSON typically is.

But the flatten method (used here with ! bang) is not working (it creates the file with no error but then the file is empty).

In my ruby file below I leave a working example of commented out code which isjust doing a simply conversion without the .flatten method. Since the JSON is an array (at the highest level) - separated by commas and enclosed in square brackets, shouldn't it take the .flatten method, just as it takes .each in the working commented out block? (This is also what the docs seems to indicate!)

require 'csv'
require 'json'

# CSV.open('false-hotels-merged.csv', 'w') do |csv|
#   JSON.parse(File.open('monfri-false-hotels-merged.json').read).each do |hash|
#     csv << hash.values
#   end
# end

CSV.open('wed-all-false-hotels.csv', 'w') do |csv|
  JSON.parse(File.open('monfri-false-hotels-merged.json').read).flatten! do |f|
    csv << f.values
  end
end

Example JSON data snippet:

[...
        {
          "id": "111707",
          "name": "Seven Park Place by William Drabble",
          "phone": "+442073161600",
          "email": "[email protected]",
          "website": "http://www.stjameshotelandclub.com/michelin-star-chef-william-drabble",
          "location": {
            "latitude": 51.5062548,
            "longitude": -0.1403209,
            "address": {
              "line1": "7-8 Park Place",
              "line2": "St James's",
              "line3": "",
              "postcode": "SW1A 1LP",
              "city": "London",
              "country": "UK"
            }
          }
        },
        {
          "id": "104493",
          "name": "Seymour's Restaurant & Bar",
          "phone": "+442079352010",
          "email": "[email protected]",
          "website": "http://www.theleonard.com",
          "location": {
            "latitude": 51.51463,
            "longitude": -0.15779,
            "address": {
              "line1": "15 Seymour Street",
              "line2": "",
              "line3": "",
              "postcode": "W1H 7JW",
              "city": "London",
              "country": "UK"
            }
          }
        },
        {
          "id": "250922",
          "name": "Shaka Zulu",
          "phone": "+442033769911",
          "email": "[email protected]",
          "website": "http://www.shaka-zulu.com/",
          "location": {
            "latitude": 51.5414979,
            "longitude": -0.1458655,
            "address": {
              "line1": "Stables Market ",
              "line2": "Camden",
              "line3": "",
              "postcode": "NW1 8AB",
              "city": "London",
              "country": "UK"
            }
          }
        }
    ]

Again, no errors at all in the terminal - just blank CSV file created.

Upvotes: 0

Views: 654

Answers (2)

Mario Zannone
Mario Zannone

Reputation: 2883

Try this:

require 'csv'
require 'json'

def hflat(h)
  h.values.flat_map {|v| v.is_a?(Hash) ? hflat(v) : v }
end

CSV.open('file.csv', 'w') do |csv|
  JSON.parse(File.open('file.json').read).each do |h| 
    csv << hflat(h)
  end
end

Upvotes: 1

Martin Vidner
Martin Vidner

Reputation: 2337

Array#flatten only flattens arrays. There is also Hash#flatten, which also produces an array. You seem to want to flatten a nested Hash for which I don't know of a library method.

It seems that your result is empty because there's an .each missing after the flatten - the block is simply not run.

Upvotes: 3

Related Questions