Remove a key:value from an JSON object using jq
Asked Answered
A

5

24

I’m trying to add and remove a 'key:value' from a JSON object using jq. I’m new using jq and I do not understand the errors that jq is throwing at me, so any help pushing me in the correct direction is greatly appreciated. My specific issue is I have a JSON object (below) and I want to be able to add/remove the “maxHeight” key/value from the JSON object.

Some commands I’ve tried with the errors I get…

jq 'recurse(.[]) |= del(.maxHeight)' new.json   

Cannot iterate over null (null)

 jq 'recurse(.[]) |= {maxHeight}' new.json

Cannot iterate over string ("feature")

jq 'recurse(.[]) |= .maxHeight' new.json 

Cannot index string with string "style"

new.json file looks like this...

{
  "style": {
    "className": "feature",
    "showLabels": false,
    "color": "function(feature, variableName, glyphObject, track){if(feature.get(\"type\") === \"CDS\"){return \"#9CFBF5\";} else if(feature.get(\"type\") === \"exon\"){return \"#43A47F\";} else if(feature.get(\"type\") === \"intron\"){return \"#E8E8E8\";} else if(feature.get(\"type\") === \"five_prime_UTR\"){return \"#F192FE\";} else if(feature.get(\"type\") === \"three_prime_UTR\"){return \"#FEC892\";} else {return \"#FF0000\";}}",
    "arrowheadClass": null,
    "featureCss": "padding:3px;"
  },
  "menuTemplate": [
    {
      "label": "View details"
    },
    {
      "label": "Highlight a gene"
    },
    {
      "iconClass": "dijitIconBookmark",
      "content": "function(track,feature,div) { window.parent.angular.element(window.frameElement).scope().specificNote( feature[2] ) }",
      "action": "contentDialog",
      "title": "(feature{name})",
      "label": "Create Note"
    }
  ],
  "hooks": {
    "modify": " function(track,feature,div){   var checkArr=[\"Reference\",\"Missing\",\"Heterozygous\",\"NonReference\"];for(var i=0;i<feature.length;i++){for(var j=0;j<checkArr.length;j++){  if( i>3) { if( feature[i] ===  checkArr[j] ) {  if(feature[i]==\"NonReference\"){div.style.backgroundColor=\"red\"}else if(feature[i]==\"Reference\"){div.style.backgroundColor=\"green\"}else if(feature[i]==\"Heterozygous\"){div.style.backgroundColor=\"orange\"}else if(feature[i]==\"Missing\"){div.style.backgroundColor=\"grey\"} }}}}} "
  },
  "key": "cucumber_ChineseLong_v2.gff3",
  "storeClass": "JBrowse/Store/SeqFeature/NCList",
  "trackType": null,
  "maxHeight": "200px",
  "urlTemplate": "tracks/cucumber_ChineseLong_v2.gff3/{refseq}/trackData.json",
  "compress": 0,
  "label": "cucumber_ChineseLong_v2.gff3",
  "type": "JBrowse/View/Track/CanvasFeatures"
}
Animalize answered 30/1, 2018 at 19:21 Comment(0)
I
42

Using jq-1.6, this deletes the key .maxHeight from the input (it doesn't even complain if it didn't exist before):

jq 'del(.maxHeight)' new.json
Indifferent answered 17/3, 2020 at 13:23 Comment(1)
you mean echo '{ "a": 1, "b": 2 }' | jq 'del(.a)' >output.json or echo '{ "a": 1, "b": 2 }' >input.json; jq 'del(.a)' input.json >output.json or echo '{ "a": 1, "b": 2 }' >input.json; jq 'del(.a)' input.json | sponge input.json with sponge from moreutilsWithin
T
7

There are two approaches:

  • the targeted approach, illustrated in an answer to your previous question at Manipulating a JSON file with jq

  • the global approach, that ignores the specific context.

The following illustrates the global approach:

walk(if type == "object" and has("maxHeight") then del(.maxHeight) else . end)

This in effect "edits" the input by updating whichever objects have the specified key.

If your jq does not have walk/1 simply include its def (available e.g. from https://raw.githubusercontent.com/stedolan/jq/master/src/builtin.jq) before invoking it.

Truth answered 30/1, 2018 at 20:7 Comment(2)
Sorry to ask a dumb question, but how on earth to "include its def before invoking it"? I am using jq from bash, not sure where to put the functionCaseation
@Caseation see my answerDygall
C
2

I had a similar issue, but did not want to make a lot of code for this or spend too much time on it.

I'm assuming you fixed your reason for this. But for me, the following worked for a value that I did not have to recursively look for, i.e. only at the top level. Also, I did not care if a blank/null value was there:

jq "if .maxHeight then .maxHeight = null else . end "
Cottier answered 4/2, 2019 at 14:11 Comment(0)
T
1

For very large JSON documents, it may be preferable to use jq's "streaming parser" for this kind of problem, at least if the editing operations greatly reduce the size of the document. At any rate, here is a solution that uses the --stream option:

jq --stream 'select(length == 2 and .[0][-1] == "maxHeight" | not)' new.json |
 jq -n 'fromstream(inputs)'

Note that the -n option must be used in the second call to jq.

Truth answered 30/1, 2018 at 20:31 Comment(0)
D
1

Here is an example removing a couple of keys from an Electrum Wallet JSON file, this was tested in zsh and bash with a verison of jq that doesn't have walk built in:

jq -f <(
  curl https://raw.githubusercontent.com/stedolan/jq/master/src/builtin.jq
  echo 'walk('
  for i in transactions spent_outpoints verified_tx3 txo txi addresses addr_history; do
    echo 'if type == "object" and has("'"$i"'") then del(.'"$i"') else . end |'
  done
  echo '.)'
)  ~/.electrum/testnet/wallets/default_wallet
Dygall answered 3/8, 2018 at 9:44 Comment(1)
ah cool, so it's just enough to have the jq file right there in the first placeCaseation

© 2022 - 2024 — McMap. All rights reserved.