BilalReffas
BilalReffas

Reputation: 8328

Altering and updating a JSON file

I wrote a small script which loops my current Jsonfile but it's not possible to append a key and value.

This is my file

[
  {
    "URL": "https://p59-caldav.icloud.com",
  }
]

I would like to append a key and value like this

[
  {
    "URL": "https://p59-caldav.icloud.com",
    "test": "test"
  }
]

My current script setup

#!/usr/bin/env ruby

require 'rubygems'
require 'json'
require 'domainatrix'

jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
array = JSON.parse(jsonHash)

File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|

  array.each do |child|
    url = Domainatrix.parse(child["URL"])
    json = {
      "url" => child["URL"],
      "provider" => url.domain,
      "service" => url.subdomain,
      "context" =>  url.path,
      "suffix" => url.public_suffix
    }

    f.write(JSON.pretty_generate(json))
  end
end

The script overwrite my whole jsonfile...this is not what I want :/

Upvotes: 0

Views: 2211

Answers (2)

the Tin Man
the Tin Man

Reputation: 160571

This is untested but looks about right:

ORIGINAL_JSON = 'sampleData.json'
NEW_JSON = ORIGINAL_JSON + '.new'
OLD_JSON = ORIGINAL_JSON + '.old'

json = JSON.parse(File.read(ORIGINAL_JSON))

ary = json.map do |child|
  url = Domainatrix.parse(child['URL'])
  {
    'url' => child['URL'],
    'provider' => url.domain,
    'service' => url.subdomain,
    'context' => url.path,
    'suffix' => url.public_suffix
  }
end

File.write(NEW_JSON, ary.to_json)

File.rename(ORIGINAL_JSON, OLD_JSON)
File.rename(NEW_JSON, ORIGINAL_JSON)
File.delete(OLD_JSON)

It's important to not overwrite the original file until all processing has occurred, hence writing to a new file, closing the new and old, then renaming the old one to something safe, renaming the new to the original name, and then being able to remove the original. If you don't follow a process like that you run a risk of corrupting or losing your original data if the code or machine crashes mid-stream.

See "How to search file text for a pattern and replace it with a given value" for more information.

Upvotes: 2

mattbornski
mattbornski

Reputation: 12553

Probably the simplest way to use f.write would be to use it to replace the entire contents of the file. With that in mind, let's see if we can compose what we want the entire contents of the file to be, in memory, and then write it.

#!/usr/bin/env ruby

require 'rubygems'
require 'json'
require 'domainatrix'

write_array = []
jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
read_array = JSON.parse(jsonHash)
read_array.each do |child|
    url = Domainatrix.parse(child["URL"])
    write_array << {
        "url" => child["URL"],
        "provider" => url.domain,
        "service" => url.subdomain,
        "context" =>  url.path,
        "suffix" => url.public_suffix
    }
end

File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|
    f.write(JSON.pretty_generate(write_array))
end

Note some changes:

  1. Fixed indentation :)
  2. Removed some nesting
  3. Write once with the entire contents of the file. Unless you have a really big file or a really important need for pipelined I/O this is probably the simplest thing to do.

Upvotes: 1

Related Questions