1

I have a json object. It has multiple fields "passthrough_fields" which is unnecessary for me and I want to remove them. Is there a way to get all those attributes filtered out? JSON:

{
"type": "playable_item",
"id": "p06s0lq7",
"urn": "urn:bbc:radio:episode:p06s0mk3",
"network": {
    "id": "bbc_radio_five_live",
    "key": "5live",
    "short_title": "Radio 5 live",
    "logo_url": "https://sounds.files.bbci.co.uk/v2/networks/bbc_radio_five_live/{type}_{size}.{format}",
    "passthrough_fields": {}
},
"titles": {
    "primary": "Replay",
    "secondary": "Bill Shankly",
    "tertiary": null,
    "passthrough_fields": {}
},
"synopses": {
    "short": "Bill Shankly with Sue MacGregor in 1979 - five years after he resigned as Liverpool boss.",
    "medium": null,
    "long": "Bill Shankly in conversation with Sue MacGregor in 1979, five years after he resigned as Liverpool manager.",
    "passthrough_fields": {}
},
"image_url": "https://ichef.bbci.co.uk/images/ic/{recipe}/p06qbz1x.jpg",
"duration": {
    "value": 1774,
    "label": "29 mins",
    "passthrough_fields": {}
},
"progress": null,
"container": {
    "type": "series",
    "id": "p06qbzmj",
    "urn": "urn:bbc:radio:series:p06qbzmj",
    "title": "Replay",
    "synopses": {
        "short": "Colin Murray unearths classic sports commentaries and interviews from the BBC archives.",
        "medium": "Colin Murray looks back at 90 years of sport on the BBC by unearthing classic commentaries and interviews from the BBC archives.",
        "long": null,
        "passthrough_fields": {}
    },
    "activities": [],
    "passthrough_fields": {}
},
"availability": {
    "from": "2018-11-16T16:18:54Z",
    "to": null,
    "label": "Available for over a year",
    "passthrough_fields": {}
},
"guidance": {
    "competition_warning": false,
    "warnings": null,
    "passthrough_fields": {}
},
"activities": [],
"uris": [
    {
        "type": "latest",
        "label": "Latest",
        "uri": "/v2/programmes/playable?container=p06qbzmj&sort=sequential&type=episode",
        "passthrough_fields": {}
    }
],
"passthrough_fields": {}
}

Is there a way I can remove all those fields and store the updated json in a new variable?

SRack
  • 11,495
  • 5
  • 47
  • 60
Nipun Tanay
  • 59
  • 1
  • 5

3 Answers3

1

You can do this recursively to tackle nested occurances of passthrough_fields, whether they're found in an array or a sub hash. Inline comments to explain things a little as it goes:

hash = JSON.parse(input) # convert the JSON to a hash

def remove_recursively(hash, *to_remove)
  hash.each do |key, val|
    hash.except!(*to_remove) # the heavy lifting: remove all keys that match `to_remove`

    remove_recursively(val, *to_remove) if val.is_a? Hash # if a nested hash, run this method on it

    if val.is_a? Array # if a nested array, loop through this checking for hashes to run this method on
      val.each { |el| remove_recursively(el, *to_remove) if el.is_a? Hash } 
    end
  end
end

remove_recursively(hash, 'passthrough_fields')

To demonstrate, with a simplified example:

hash =  { 
          "test" => { "passthrough_fields" => [1, 2, 3], "wow" => '123' }, 
          "passthrough_fields" => [4, 5, 6],
          "array_values" => [{ "to_stay" => "I am", "passthrough_fields" => [7, 8, 9]}]
        }

remove_recursively(hash, 'passthrough_fields')
#=> {"test"=>{"wow"=>"123"}, "array_values"=>[{"to_stay"=>"I am"}]}

remove_recursively(hash, 'passthrough_fields', 'wow', 'to_stay')
#=> {"test"=>{}, "array_values"=>[{}]}

This will tackle any arrays, and will dig for nested hashes however deep it needs to go.

It takes any number of fields to remove, in this case a single 'passthrough_fields'.

Hope this helps, let me know how you get on.

SRack
  • 11,495
  • 5
  • 47
  • 60
0

I think that the easiest solution would be to:

  1. convert JSON into hash (JSON.parse(input))

  2. use this answer to extend the functionality of Hash (save it in config/initializers/except_nested.rb)

  3. on the hash from 1st step, call:

    without_passthrough = your_hash.except_nested('passthrough_fields')

  4. covert hash to JSON (without_passthrough.to_json)

Please keep in mind that it will work for passthrough_fields that is nested directly in hashes. In your JSON, you have the following part:

"uris" => [
  {
    "type"=>"latest",
    "label"=>"Latest",
    "uri"=>"/v2/programmes/playable?container=p06qbzmj&sort=sequential&type=episode",
"passthrough_fields"=>{}
  }
]

In this case, the passthrough_fields will not be removed. You have to find a more sophisticated solution :)

MrShemek
  • 2,413
  • 1
  • 16
  • 20
0

You can do something like this:

def nested_except(hash, except_key)
  sanitized_hash = {}
  hash.each do |key, value|
    next if key == except_key
    sanitized_hash[key] = value.is_a?(Hash) ? nested_except(value, except_key) : value
  end
  sanitized_hash
end

json = JSON.parse(json_string)
sanitized = nested_except(json, 'passthrough_fields')

See example:

json = { :a => 1, :b => 2, :c => { :a => 1, :b => { :a => 1 } } }
nested_except(json, :a)
# => {:b=>2, :c=>{:b=>{}}}

This helper can easily be converted to support multiple keys to except, simply by except_keys = Array.wrap(except_key) and next if except_keys.include?(key)

MrYoshiji
  • 54,334
  • 13
  • 124
  • 117